diff --git a/HandDriver/package.json b/HandDriver/package.json deleted file mode 100644 index 6e02ee7..0000000 --- a/HandDriver/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ -"name": "com.udexreal.handdriver", -"displayName": "HandDriver", -"description": ""HandDriver", -"version": "2.1.8", -"unity": "2022.3", -"license": "MIT", -"dependencies": { - } -} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/Model.meta b/Samples~/Hand Driver Demo/HandDriver/Model.meta new file mode 100644 index 0000000..688f455 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 132e3b41f20a4f94cb20406095cdb38a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg new file mode 100644 index 0000000..c157dbb Binary files /dev/null and b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg differ diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg.meta new file mode 100644 index 0000000..fe5f163 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 8589e8bfc64b93b4a8143d70c9127abd +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat new file mode 100644 index 0000000..517d8a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: vr_glove_color + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: + - _EMISSION + - _NORMALMAP + m_InvalidKeywords: [] + m_LightmapFlags: 1 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 2800000, guid: ed1b2724730cc594aa8c79b70d2deb24, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: f1ba7622665bf7e44aee3f43fc62e51d, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat.meta new file mode 100644 index 0000000..8abd4ee --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a824637846136a043bd018d27422dfd7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx new file mode 100644 index 0000000..59a52fc Binary files /dev/null and b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx differ diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx.meta new file mode 100644 index 0000000..c5a9069 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: 7c6fe65dc83e437438be792aad474a5d +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png new file mode 100644 index 0000000..4f41129 Binary files /dev/null and b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png differ diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png.meta new file mode 100644 index 0000000..e75290c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 3748dee6899f1094a9133c221951f5e9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 1 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx new file mode 100644 index 0000000..1e6f88c Binary files /dev/null and b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx differ diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx.meta new file mode 100644 index 0000000..2a21c85 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: c4e403660ace5984b8a2ec3594efa03b +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx b/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx new file mode 100644 index 0000000..7a0ca5e Binary files /dev/null and b/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx differ diff --git a/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx.meta b/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx.meta new file mode 100644 index 0000000..a05ccc4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: fd5d3b6f78f09274297fdd339530e6cf +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/Plugins.meta new file mode 100644 index 0000000..7451b77 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1da1eafda489e846a172d3f088c7de3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scenes.meta b/Samples~/Hand Driver Demo/HandDriver/Scenes.meta new file mode 100644 index 0000000..838b3a8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5af45222e699f84e97cbe0f5a9e4275 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity b/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity new file mode 100644 index 0000000..f84336e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity @@ -0,0 +1,2561 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &178908012 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 178908015} + - component: {fileID: 178908014} + - component: {fileID: 178908013} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &178908013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &178908014 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &178908015 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.12 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0.2588191, y: 0, z: 0, w: 0.9659258} + m_LocalPosition: {x: 0, y: 0.224, z: -0.1927} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 30, y: 0, z: 0} +--- !u!1 &1669286643 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1669286644} + - component: {fileID: 1669286645} + m_Layer: 0 + m_Name: Network + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1669286644 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1669286643} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1669286645 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1669286643} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d694a138ada737547be655b517ff143b, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 5555 +--- !u!4 &6322760157043851 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5932072128168019068} + m_LocalRotation: {x: 0.021973813, y: -0.037681088, z: -0.00082876993, w: 0.9990479} + m_LocalPosition: {x: 0.033171818, y: -0.00011021454, z: 0.0025033744} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 748470603218601360} + m_Father: {fileID: 2363757037305591233} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &214446489185135024 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8616749464320553597} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.00015978699, y: -0.0000319244, z: -0.00062570896} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4537819508369877214} + - {fileID: 8507005058661572490} + - {fileID: 5459949832865448039} + - {fileID: 2229113852275956350} + - {fileID: 860842083862283927} + m_Father: {fileID: 6394284460539294940} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &508315818274862559 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 556059018601076370} + m_Layer: 0 + m_Name: R_Pinky_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &556059018601076370 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 508315818274862559} + m_LocalRotation: {x: 0.000000022217463, y: -0.10944835, z: 0.0000000024463613, w: 0.9939925} + m_LocalPosition: {x: 0.06285565, y: 0.0000001417291, z: -0.00000027477583} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 925978096007585036} + m_Father: {fileID: 5459949832865448039} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &671979400434968908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4522263793486564093} + m_LocalRotation: {x: -0.00036969496, y: -0.004359701, z: -0.084519185, w: 0.9964123} + m_LocalPosition: {x: 0.07088554, y: -0.0000000031225003, z: -0.000000002885508} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2363757037305591233} + m_Father: {fileID: 8507005058661572490} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &675677663783772807 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160665490735513148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff3bfb33faef00d40880dd5952fd19e9, type: 3} + m_Name: + m_EditorClassIdentifier: + Network: {fileID: 0} + CharacterName: + Hand: 1 + Thumb1: {fileID: 860842083862283927} + Thumb2: {fileID: 8310384518608653617} + Thumb3: {fileID: 7303445391904380631} + Index1: {fileID: 5496311818784395322} + Index2: {fileID: 1112424348290694685} + Index3: {fileID: 4999533632160155606} + Middle1: {fileID: 671979400434968908} + Middle2: {fileID: 2363757037305591233} + Middle3: {fileID: 6322760157043851} + Ring1: {fileID: 3758562999754509161} + Ring2: {fileID: 3396408153264893052} + Ring3: {fileID: 3820432234125702229} + Pinky1: {fileID: 556059018601076370} + Pinky2: {fileID: 925978096007585036} + Pinky3: {fileID: 4925989245680324873} + Wrist: {fileID: 214446489185135024} + Pitch: 2 + Roll: 0 + Yaw: 1 + HasIMU: 0 + coefficient: 0.6 + Thumb1Offset: {x: 0, y: 0, z: 0} + NeedRealTransfrom: 1 + UsingNetwork: 1 + UsingAndroidService: 0 + thumb1: {x: 0, y: 0, z: 0} + thumb2: {x: 0, y: 0, z: 0} + thumb3: {x: 0, y: 0, z: 0} + index1: {x: 0, y: 0, z: 0} + index2: {x: 0, y: 0, z: 0} + index3: {x: 0, y: 0, z: 0} + middle1: {x: 0, y: 0, z: 0} + middle2: {x: 0, y: 0, z: 0} + middle3: {x: 0, y: 0, z: 0} + ring1: {x: 0, y: 0, z: 0} + ring2: {x: 0, y: 0, z: 0} + ring3: {x: 0, y: 0, z: 0} + pinky1: {x: 0, y: 0, z: 0} + pinky2: {x: 0, y: 0, z: 0} + pinky3: {x: 0, y: 0, z: 0} + Joy_X: 0 + Joy_Y: 0 + Button_A: 0 + Button_B: 0 + Button_Joystick: 0 + Button_Menu: 0 + SendBackIP: + Duration1: 1 + Amplitude1: 4 + Duration2: 1 + Amplitude2: 4 +--- !u!4 &748470603218601360 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6502233864751575502} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.025892606, y: -0.000000073447595, z: 0.000000050336155} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6322760157043851} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &860842083862283927 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6172359427428232399} + m_LocalRotation: {x: -0.27638686, y: -0.77303576, z: 0.18202926, w: 0.54119444} + m_LocalPosition: {x: -0.017913787, y: 0.029178023, z: 0.025298309} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8310384518608653617} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &925079791689987278 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3396408153264893052} + m_Layer: 0 + m_Name: R_Ring_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &925978096007585036 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5676528384244021321} + m_LocalRotation: {x: -0.056468494, y: 0.022603612, z: -0.0054254225, w: 0.9981338} + m_LocalPosition: {x: 0.029873928, y: 0.000000044091582, z: -0.00000006424834} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4925989245680324873} + m_Father: {fileID: 556059018601076370} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1092894868255631846 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6643260513880387009} + m_Layer: 0 + m_Name: L_Thumb_0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1112424348290694685 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6623980709240243409} + m_LocalRotation: {x: 0.07859818, y: -0, z: -0, w: 0.9969064} + m_LocalPosition: {x: 0.043286275, y: 0.000000013968487, z: -0.000000010911709} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4999533632160155606} + m_Father: {fileID: 5496311818784395322} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1160665490735513148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6394284460539294940} + - component: {fileID: 675677663783772807} + m_Layer: 0 + m_Name: Hand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1179545435151648496 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7449938260141068636} + m_Layer: 0 + m_Name: L_Ring_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1483641636172510471 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4437782591943742735} + m_LocalRotation: {x: 0.07859818, y: 0.000000044112156, z: -0.0000000034778946, w: 0.9969064} + m_LocalPosition: {x: -0.043286555, y: -1.11022296e-17, z: -1.7763568e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6900825591207550507} + m_Father: {fileID: 7119035830311120303} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1516923936631502984 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4537819508369877214} + m_Layer: 0 + m_Name: finger_index_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1563334061762160884 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4364775665665897489} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff3bfb33faef00d40880dd5952fd19e9, type: 3} + m_Name: + m_EditorClassIdentifier: + Network: {fileID: 0} + CharacterName: + Hand: 0 + Thumb1: {fileID: 6643260513880387009} + Thumb2: {fileID: 4860356083035197191} + Thumb3: {fileID: 5635012544043017313} + Index1: {fileID: 7119035830311120303} + Index2: {fileID: 1483641636172510471} + Index3: {fileID: 6900825591207550507} + Middle1: {fileID: 5926497155746532566} + Middle2: {fileID: 6220949525431291807} + Middle3: {fileID: 8250436794041268563} + Ring1: {fileID: 7449938260141068636} + Ring2: {fileID: 3476454750331030500} + Ring3: {fileID: 5745576405633313402} + Pinky1: {fileID: 5923872426823328339} + Pinky2: {fileID: 3139369216477100124} + Pinky3: {fileID: 7188099592734048766} + Wrist: {fileID: 8464987222797490959} + Pitch: 2 + Roll: 0 + Yaw: 1 + HasIMU: 0 + coefficient: 0.6 + Thumb1Offset: {x: 0, y: 0, z: 0} + NeedRealTransfrom: 1 + UsingNetwork: 1 + UsingAndroidService: 0 + thumb1: {x: 0, y: 0, z: 0} + thumb2: {x: 0, y: 0, z: 0} + thumb3: {x: 0, y: 0, z: 0} + index1: {x: 0, y: 0, z: 0} + index2: {x: 0, y: 0, z: 0} + index3: {x: 0, y: 0, z: 0} + middle1: {x: 0, y: 0, z: 0} + middle2: {x: 0, y: 0, z: 0} + middle3: {x: 0, y: 0, z: 0} + ring1: {x: 0, y: 0, z: 0} + ring2: {x: 0, y: 0, z: 0} + ring3: {x: 0, y: 0, z: 0} + pinky1: {x: 0, y: 0, z: 0} + pinky2: {x: 0, y: 0, z: 0} + pinky3: {x: 0, y: 0, z: 0} + Joy_X: 0 + Joy_Y: 0 + Button_A: 0 + Button_B: 0 + Button_Joystick: 0 + Button_Menu: 0 + SendBackIP: + Duration1: 1 + Amplitude1: 4 + Duration2: 1 + Amplitude2: 4 +--- !u!1 &1674725905380849052 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2139789476852871069} + m_Layer: 0 + m_Name: finger_middle_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1779072659313887930 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5459949832865448039} + m_Layer: 0 + m_Name: finger_pinky_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1782205013996300363 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8133983289645034287} + m_LocalRotation: {x: 0.5501436, y: 0.49554786, z: -0.4298879, w: 0.5166923} + m_LocalPosition: {x: -0.00051342254, y: -0.0065451264, z: 0.01634766} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7449938260141068636} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1818453212030041328 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8464987222797490959} + m_Layer: 0 + m_Name: L_Wrist + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1960731104228096300 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4509120418126981120} + m_Layer: 0 + m_Name: finger_thumb_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2118207532678258419 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6220949525431291807} + m_Layer: 0 + m_Name: L_Middle_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2134795069316445640 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5635012544043017313} + m_Layer: 0 + m_Name: L_Thumb_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2139789476852871069 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674725905380849052} + m_LocalRotation: {x: 6.929678e-16, y: -1.0408341e-17, z: 1.2490009e-16, w: 1} + m_LocalPosition: {x: -0.025892286, y: -1.2686682e-10, z: 1.2212453e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8250436794041268563} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &2229113852275956350 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8620878470580026006} + m_LocalRotation: {x: -0.5166923, y: -0.42988783, z: -0.49554786, w: 0.55014354} + m_LocalPosition: {x: 0.000513423, y: -0.0065451255, z: 0.016347708} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3758562999754509161} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2246016610202118684 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3139369216477100124} + m_Layer: 0 + m_Name: L_Pinky_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2336373233828122417 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7188099592734048766} + m_Layer: 0 + m_Name: L_Pinky_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2363757037305591233 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8775219295573228795} + m_LocalRotation: {x: -0.02197379, y: 0.037680954, z: 0.00082878245, w: 0.9990479} + m_LocalPosition: {x: 0.043108307, y: 0.00000005420781, z: 0.000000008444194} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6322760157043851} + m_Father: {fileID: 671979400434968908} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2745479420465899924 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3820432234125702229} + m_Layer: 0 + m_Name: R_Ring_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!137 &3004210974051931016 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5078406064857293169} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 3 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d28ff85c01985904bb98e5bc03251ff7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + serializedVersion: 2 + m_Quality: 0 + m_UpdateWhenOffscreen: 0 + m_SkinnedMotionVectors: 1 + m_Mesh: {fileID: 7927821202470849677, guid: 0305e3a35dffee44ea72d74b0d43fada, type: 3} + m_Bones: + - {fileID: 8742907838159378579} + - {fileID: 8464987222797490959} + - {fileID: 7771250235619228355} + - {fileID: 7119035830311120303} + - {fileID: 1483641636172510471} + - {fileID: 6900825591207550507} + - {fileID: 3022463771160063853} + - {fileID: 8477920962704591765} + - {fileID: 5926497155746532566} + - {fileID: 6220949525431291807} + - {fileID: 8250436794041268563} + - {fileID: 2139789476852871069} + - {fileID: 3238773086400040756} + - {fileID: 5923872426823328339} + - {fileID: 3139369216477100124} + - {fileID: 7188099592734048766} + - {fileID: 7788326014204426005} + - {fileID: 1782205013996300363} + - {fileID: 7449938260141068636} + - {fileID: 3476454750331030500} + - {fileID: 5745576405633313402} + - {fileID: 4317057570492409822} + - {fileID: 6643260513880387009} + - {fileID: 4860356083035197191} + - {fileID: 5635012544043017313} + - {fileID: 4509120418126981120} + m_BlendShapeWeights: [] + m_RootBone: {fileID: 8742907838159378579} + m_AABB: + m_Center: {x: 0.009932702, y: 0.01853694, z: 0.0827613} + m_Extent: {x: 0.05911108, y: 0.08356892, z: 0.11045481} + m_DirtyAABB: 0 +--- !u!4 &3022463771160063853 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5453305861822447136} + m_LocalRotation: {x: -0.087871745, y: -0.02274727, z: 0.0020071317, w: 0.99587005} + m_LocalPosition: {x: -0.02279774, y: -0.00018246654, z: -0.0010259174} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6900825591207550507} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3138456007448757676 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6784752715258439899} + m_LocalRotation: {x: -0.087871745, y: -0.02274727, z: 0.0020071317, w: 0.99587005} + m_LocalPosition: {x: 0.022797322, y: 0.0001825119, z: 0.0010259576} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4999533632160155606} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3139369216477100124 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2246016610202118684} + m_LocalRotation: {x: -0.056468446, y: 0.022603612, z: -0.005425421, w: 0.9981338} + m_LocalPosition: {x: -0.02987433, y: -3.0362518e-10, z: 1.02140514e-16} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7188099592734048766} + m_Father: {fileID: 5923872426823328339} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3194403237188042529 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8507005058661572490} + m_Layer: 0 + m_Name: finger_middle_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3238773086400040756 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5356405478463241161} + m_LocalRotation: {x: 0.5057481, y: 0.6016364, z: -0.36057425, w: 0.50223374} + m_LocalPosition: {x: 0.0024781574, y: -0.018981375, z: 0.01521364} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5923872426823328339} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3380521005008719725 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3974759597271355457} + m_Layer: 0 + m_Name: finger_pinky_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3396408153264893052 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 925079791689987278} + m_LocalRotation: {x: -0.021056127, y: 0.040366974, z: 0.00085085473, w: 0.9989627} + m_LocalPosition: {x: 0.040331636, y: -0.000000052882314, z: 0.000000042945093} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3820432234125702229} + m_Father: {fileID: 3758562999754509161} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3404879038379191373 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4317057570492409822} + m_Layer: 0 + m_Name: finger_ring_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3476454750331030500 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8699629255588642349} + m_LocalRotation: {x: -0.021056127, y: 0.040366974, z: 0.00085085473, w: 0.9989627} + m_LocalPosition: {x: -0.040331233, y: 1.5543122e-17, z: 1.5543122e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5745576405633313402} + m_Father: {fileID: 7449938260141068636} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3758562999754509161 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4793669001851238087} + m_LocalRotation: {x: -0.0017315906, y: -0.05142107, z: -0.03361232, w: 0.99810976} + m_LocalPosition: {x: 0.06597489, y: 0.000000019857714, z: -0.000000027218801} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3396408153264893052} + m_Father: {fileID: 2229113852275956350} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3820432234125702229 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2745479420465899924} + m_LocalRotation: {x: 0.021056125, y: -0.04036691, z: -0.0008508534, w: 0.9989627} + m_LocalPosition: {x: 0.028395722, y: -0.00009681354, z: 0.0022965616} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5249512097504350987} + m_Father: {fileID: 3396408153264893052} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3823084560694368822 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7119035830311120303} + m_Layer: 0 + m_Name: L_Index_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &3823939030950422181 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5496311818784395322} + m_Layer: 0 + m_Name: R_Index_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &3930443889687988978 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8310384518608653617} + m_Layer: 0 + m_Name: R_Thumb_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3974759597271355457 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3380521005008719725} + m_LocalRotation: {x: 0.1958613, y: 0.05253276, z: 0.0105080465, w: 0.97916716} + m_LocalPosition: {x: 0.017914427, y: 0.00074151315, z: -0.0017793871} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4925989245680324873} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4317057570492409822 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3404879038379191373} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.022430142, y: -1.3368179e-10, z: 2.40085e-10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5745576405633313402} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4325783370303563264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4925989245680324873} + m_Layer: 0 + m_Name: R_Pinky_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4364775665665897489 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8742907838159378579} + - component: {fileID: 1563334061762160884} + m_Layer: 0 + m_Name: Hand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4437782591943742735 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1483641636172510471} + m_Layer: 0 + m_Name: L_Index_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4509120418126981120 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1960731104228096300} + m_LocalRotation: {x: 1.2490009e-16, y: -1.3866696e-32, z: -1.110223e-16, w: 1} + m_LocalPosition: {x: -0.030464003, y: -5.2252597e-10, z: -7.5495166e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5635012544043017313} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4522263793486564093 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 671979400434968908} + m_Layer: 0 + m_Name: R_Middle_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4537819508369877214 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516923936631502984} + m_LocalRotation: {x: -0.550753, y: -0.53957784, z: -0.3514343, w: 0.5310563} + m_LocalPosition: {x: -0.001557247, y: 0.021073224, z: 0.014787008} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5496311818784395322} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4763710838890118350 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8477920962704591765} + m_Layer: 0 + m_Name: finger_middle_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4793669001851238087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3758562999754509161} + m_Layer: 0 + m_Name: R_Ring_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4858515839211149561 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5926497155746532566} + m_Layer: 0 + m_Name: L_Middle_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4860356083035197191 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6469635495150361924} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.04040613, y: -1.3322676e-17, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5635012544043017313} + m_Father: {fileID: 6643260513880387009} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4925989245680324873 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4325783370303563264} + m_LocalRotation: {x: -0.13968116, y: -0.07503679, z: -0.012569679, w: 0.98726934} + m_LocalPosition: {x: 0.017959304, y: 0.00014881363, z: 0.0008222517} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3974759597271355457} + m_Father: {fileID: 925978096007585036} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4938117471892091556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7026629995582796419} + - component: {fileID: 4986107754757140926} + m_Layer: 0 + m_Name: RightHand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4971920943665295888 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8110118852186649490} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.030463943, y: 0.00000016772235, z: 0.00000011913329} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7303445391904380631} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!54 &4986107754757140926 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4938117471892091556} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 3 +--- !u!4 &4999533632160155606 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8176732961496558883} + m_LocalRotation: {x: 0.009326217, y: 0.022519214, z: -0.0037888263, w: 0.9996957} + m_LocalPosition: {x: 0.02827551, y: -0.000000076228126, z: -0.00000002183206} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3138456007448757676} + m_Father: {fileID: 1112424348290694685} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5078406064857293169 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5879237088916054589} + - component: {fileID: 3004210974051931016} + m_Layer: 0 + m_Name: vr_glove_left_slim + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5249512097504350987 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6221956022301426475} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.022430038, y: 0.000000040019266, z: 0.00000003203466} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3820432234125702229} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5309327284228994370 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6900825591207550507} + m_Layer: 0 + m_Name: L_Index_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5333547042377003323 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8694312561512733603} + - component: {fileID: 7913584612207383781} + m_Layer: 0 + m_Name: LeftHand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5356405478463241161 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3238773086400040756} + m_Layer: 0 + m_Name: finger_pinky_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5453305861822447136 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3022463771160063853} + m_Layer: 0 + m_Name: finger_index_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5459949832865448039 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1779072659313887930} + m_LocalRotation: {x: -0.50223374, y: -0.36057425, z: -0.6016364, w: 0.5057481} + m_LocalPosition: {x: -0.002478157, y: -0.018981375, z: 0.015213609} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 556059018601076370} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5496311818784395322 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3823939030950422181} + m_LocalRotation: {x: 0.007817584, y: 0.115047336, z: -0.0673426, w: 0.9910439} + m_LocalPosition: {x: 0.07379747, y: -0.00000011036788, z: 0.00000007059579} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1112424348290694685} + m_Father: {fileID: 4537819508369877214} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5635012544043017313 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2134795069316445640} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.03251682, y: -4.019752e-10, z: 8.881784e-18} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4509120418126981120} + m_Father: {fileID: 4860356083035197191} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5676528384244021321 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 925978096007585036} + m_Layer: 0 + m_Name: R_Pinky_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5745576405633313402 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6487436691325200521} + m_LocalRotation: {x: 0.021056125, y: -0.04036691, z: -0.0008508534, w: 0.9989627} + m_LocalPosition: {x: -0.028395902, y: 0.00009685899, z: -0.0022966054} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4317057570492409822} + m_Father: {fileID: 3476454750331030500} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5859416599995716932 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7933615073907520859} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7026629995582796419} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5879237088916054589 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5078406064857293169} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8694312561512733603} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5923872426823328339 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6477523313648946209} + m_LocalRotation: {x: -0.000000024055227, y: -0.10944835, z: -0.0000000026487172, w: 0.9939925} + m_LocalPosition: {x: -0.06285559, y: -0.00000015646219, z: 0.00000032782555} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3139369216477100124} + m_Father: {fileID: 3238773086400040756} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5926497155746532566 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4858515839211149561} + m_LocalRotation: {x: -0.00036969496, y: -0.004359701, z: -0.084519185, w: 0.9964123} + m_LocalPosition: {x: -0.07088554, y: 4.3298696e-17, z: 6.661338e-18} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6220949525431291807} + m_Father: {fileID: 8477920962704591765} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5932072128168019068 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6322760157043851} + m_Layer: 0 + m_Name: R_Middle_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6172359427428232399 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 860842083862283927} + m_Layer: 0 + m_Name: R_Thumb_0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6220949525431291807 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2118207532678258419} + m_LocalRotation: {x: -0.02197379, y: 0.037680954, z: 0.00082878245, w: 0.9990479} + m_LocalPosition: {x: -0.043108538, y: 2.6645352e-17, z: 2.6645352e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8250436794041268563} + m_Father: {fileID: 5926497155746532566} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6221956022301426475 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5249512097504350987} + m_Layer: 0 + m_Name: finger_ring_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6394284460539294940 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160665490735513148} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 214446489185135024} + m_Father: {fileID: 7026629995582796419} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6469635495150361924 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4860356083035197191} + m_Layer: 0 + m_Name: L_Thumb_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6477523313648946209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5923872426823328339} + m_Layer: 0 + m_Name: L_Pinky_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6487436691325200521 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5745576405633313402} + m_Layer: 0 + m_Name: L_Ring_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6502233864751575502 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 748470603218601360} + m_Layer: 0 + m_Name: finger_middle_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6623980709240243409 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1112424348290694685} + m_Layer: 0 + m_Name: R_Index_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6643260513880387009 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1092894868255631846} + m_LocalRotation: {x: -0.54119444, y: 0.18202926, z: 0.77303576, w: -0.27638686} + m_LocalPosition: {x: 0.017913802, y: 0.029178036, z: 0.025298318} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4860356083035197191} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6784752715258439899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3138456007448757676} + m_Layer: 0 + m_Name: finger_index_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6900825591207550507 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5309327284228994370} + m_LocalRotation: {x: 0.009326217, y: 0.022519171, z: -0.003788819, w: 0.9996957} + m_LocalPosition: {x: -0.028275203, y: 9.366404e-11, z: -1.4861739e-11} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3022463771160063853} + m_Father: {fileID: 1483641636172510471} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7026629995582796419 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4938117471892091556} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6394284460539294940} + - {fileID: 5859416599995716932} + m_Father: {fileID: 7268218674378355239} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7119035830311120303 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3823084560694368822} + m_LocalRotation: {x: 0.007817584, y: 0.115047336, z: -0.0673426, w: 0.9910439} + m_LocalPosition: {x: -0.073797464, y: 0.00000011920929, z: -0.000000059604645} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1483641636172510471} + m_Father: {fileID: 7771250235619228355} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7188099592734048766 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2336373233828122417} + m_LocalRotation: {x: -0.13968116, y: -0.07503679, z: -0.012569679, w: 0.98726934} + m_LocalPosition: {x: -0.017959101, y: -0.00014882295, z: -0.0008222617} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7788326014204426005} + m_Father: {fileID: 3139369216477100124} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7268218674378355236 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7268218674378355239} + m_Layer: 0 + m_Name: Interactions Hands + m_TagString: Untagged + m_Icon: {fileID: 2800000, guid: 0b09374c5d8c3464e9f29b2e29f8982c, type: 3} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7268218674378355239 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7268218674378355236} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8694312561512733603} + - {fileID: 7026629995582796419} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7303445391904380631 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7978712306862893037} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.032516796, y: -0.00000005848133, z: -0.00000003636439} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4971920943665295888} + m_Father: {fileID: 8310384518608653617} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!137 &7384835040074131152 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7933615073907520859} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 3 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d28ff85c01985904bb98e5bc03251ff7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + serializedVersion: 2 + m_Quality: 0 + m_UpdateWhenOffscreen: 0 + m_SkinnedMotionVectors: 1 + m_Mesh: {fileID: -7313324671967738410, guid: 0305e3a35dffee44ea72d74b0d43fada, type: 3} + m_Bones: + - {fileID: 214446489185135024} + - {fileID: 4537819508369877214} + - {fileID: 5496311818784395322} + - {fileID: 1112424348290694685} + - {fileID: 4999533632160155606} + - {fileID: 8507005058661572490} + - {fileID: 671979400434968908} + - {fileID: 2363757037305591233} + - {fileID: 6322760157043851} + - {fileID: 5459949832865448039} + - {fileID: 556059018601076370} + - {fileID: 925978096007585036} + - {fileID: 4925989245680324873} + - {fileID: 2229113852275956350} + - {fileID: 3758562999754509161} + - {fileID: 3396408153264893052} + - {fileID: 3820432234125702229} + - {fileID: 860842083862283927} + - {fileID: 8310384518608653617} + - {fileID: 7303445391904380631} + - {fileID: 4971920943665295888} + m_BlendShapeWeights: [] + m_RootBone: {fileID: 214446489185135024} + m_AABB: + m_Center: {x: -0.010092495, y: 0.018568892, z: 0.083387025} + m_Extent: {x: 0.059111074, y: 0.083568946, z: 0.11045482} + m_DirtyAABB: 0 +--- !u!4 &7449938260141068636 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179545435151648496} + m_LocalRotation: {x: -0.0017315906, y: -0.05142107, z: -0.03361232, w: 0.99810976} + m_LocalPosition: {x: -0.06597498, y: -0.0000000018626451, z: 1.0547119e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3476454750331030500} + m_Father: {fileID: 1782205013996300363} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7771250235619228355 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8797527941768423211} + m_LocalRotation: {x: 0.5310563, y: 0.3514343, z: -0.53957784, w: 0.550753} + m_LocalPosition: {x: 0.001557245, y: 0.02107323, z: 0.014786973} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7119035830311120303} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7788326014204426005 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117458629084437052} + m_LocalRotation: {x: 0.1958613, y: 0.05253276, z: 0.0105080465, w: 0.97916716} + m_LocalPosition: {x: -0.017914493, y: -0.00074155553, z: 0.0017794578} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7188099592734048766} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!54 &7913584612207383781 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5333547042377003323} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 3 +--- !u!1 &7933615073907520859 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5859416599995716932} + - component: {fileID: 7384835040074131152} + m_Layer: 0 + m_Name: vr_glove_right_slim + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &7978712306862893037 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7303445391904380631} + m_Layer: 0 + m_Name: R_Thumb_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8110118852186649490 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4971920943665295888} + m_Layer: 0 + m_Name: finger_thumb_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8133983289645034287 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1782205013996300363} + m_Layer: 0 + m_Name: finger_ring_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8176732961496558883 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4999533632160155606} + m_Layer: 0 + m_Name: R_Index_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8250436794041268563 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8316072831360955084} + m_LocalRotation: {x: 0.021973813, y: -0.037681088, z: -0.00082876993, w: 0.9990479} + m_LocalPosition: {x: -0.033171408, y: 0.00011017601, z: -0.002503392} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2139789476852871069} + m_Father: {fileID: 6220949525431291807} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8310384518608653617 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3930443889687988978} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.04040613, y: 0.000000032195924, z: 0.000000017957513} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7303445391904380631} + m_Father: {fileID: 860842083862283927} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8316072831360955084 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8250436794041268563} + m_Layer: 0 + m_Name: L_Middle_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8464987222797490959 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1818453212030041328} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.00015978744, y: -0.000031924377, z: -0.0006257091} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7771250235619228355} + - {fileID: 8477920962704591765} + - {fileID: 3238773086400040756} + - {fileID: 1782205013996300363} + - {fileID: 6643260513880387009} + m_Father: {fileID: 8742907838159378579} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8477920962704591765 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4763710838890118350} + m_LocalRotation: {x: 0.5617497, y: 0.41973728, z: -0.47298795, w: 0.5334232} + m_LocalPosition: {x: -0.0021773048, y: 0.0071195434, z: 0.016318835} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5926497155746532566} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8507005058661572490 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3194403237188042529} + m_LocalRotation: {x: -0.5334232, y: -0.47298795, z: -0.41973728, w: 0.5617497} + m_LocalPosition: {x: 0.002177303, y: 0.007119544, z: 0.01631881} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 671979400434968908} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8616749464320553597 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 214446489185135024} + m_Layer: 0 + m_Name: R_Wrist + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8620878470580026006 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2229113852275956350} + m_Layer: 0 + m_Name: finger_ring_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8694312561512733603 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5333547042377003323} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8742907838159378579} + - {fileID: 5879237088916054589} + m_Father: {fileID: 7268218674378355239} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8699629255588642349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3476454750331030500} + m_Layer: 0 + m_Name: L_Ring_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8742907838159378579 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4364775665665897489} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8464987222797490959} + m_Father: {fileID: 8694312561512733603} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8775219295573228795 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2363757037305591233} + m_Layer: 0 + m_Name: R_Middle_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8797527941768423211 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7771250235619228355} + m_Layer: 0 + m_Name: finger_index_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &9117458629084437052 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7788326014204426005} + m_Layer: 0 + m_Name: finger_pinky_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 diff --git a/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity.meta b/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity.meta new file mode 100644 index 0000000..6681d0b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 36465b59c462de54aab5639c7bdb7d29 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts.meta b/Samples~/Hand Driver Demo/HandDriver/Scripts.meta new file mode 100644 index 0000000..209eb9f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd6c8c2fb003c044bbafdfd19b405601 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs b/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs new file mode 100644 index 0000000..c257070 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs @@ -0,0 +1,698 @@ +using NaughtyAttributes; +using System.Collections.Generic; +using TouchSocket.Core; +using UnityEngine; + +public class HandDriver : MonoBehaviour +{ + public Network Network; + + public enum HandType + { + Left, + Right + } + + public enum Axis + { + x, + y, + z, + x_n, + y_n, + z_n + } + + public string CharacterName = string.Empty; + public HandType Hand; + private Dictionary _originQuaternionDic; + + public Transform Thumb1; + public Transform Thumb2; + public Transform Thumb3; + + public Transform Index1; + public Transform Index2; + public Transform Index3; + + public Transform Middle1; + public Transform Middle2; + public Transform Middle3; + + public Transform Ring1; + public Transform Ring2; + public Transform Ring3; + + public Transform Pinky1; + public Transform Pinky2; + public Transform Pinky3; + + public Transform Wrist; + + [Header("[Axis OffSet]")] + public Axis Pitch = Axis.x; + + public Axis Roll = Axis.y; + + public Axis Yaw = Axis.z; + + [Header("[IMU(On/Off)]")] public bool HasIMU = false; + + [Header("[Thumb Root Coefficient]")] [Range(0, 1)] public float coefficient = 0.6f; + + [Header("[Thumb Root OffSet]")] public Vector3 Thumb1Offset; + + [Header("[App Options]")] + public bool NeedRealTransfrom; + + //[HideInInspector] + public bool UsingNetwork; + + public bool UsingAndroidService; + + [Header("[Vector3 Angles]")] + public Vector3 thumb1; + public Vector3 thumb2; + public Vector3 thumb3; + + public Vector3 index1; + public Vector3 index2; + public Vector3 index3; + + public Vector3 middle1; + public Vector3 middle2; + public Vector3 middle3; + + public Vector3 ring1; + public Vector3 ring2; + public Vector3 ring3; + + public Vector3 pinky1; + public Vector3 pinky2; + public Vector3 pinky3; + + [Header("[Controller Values]")] + public float Joy_X; + public float Joy_Y; + public bool Button_A; + public bool Button_B; + public bool Button_Joystick; + public bool Button_Menu; + public InputData inputData = new(); + + [Header("[Vibration Control]")] + public string SendBackIP; + public VibrationData vibrationData; + + [BoxGroup("Vibrator 1"), Min(0), Label("Million Second")] + public int Duration1 = 20; + [BoxGroup("Vibrator 1"), Range(4, 10)] + public int Amplitude1 = 4; + [Button] + public void Vibrator_1Active() + { + if (Network == null) return; + SingleVirbator[] Virbators; + if (Hand == HandType.Left) + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(1, Duration1, Amplitude1), + new SingleVirbator() + }; + vibrationData = new VibrationData(Virbators); + } + else + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(), + new SingleVirbator(1, Duration1, Amplitude1), + }; + vibrationData = new VibrationData(Virbators); + } + Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData); + } + + [BoxGroup("Vibrator 2"), Min(0), Label("Million Second")] + public int Duration2 = 20; + [BoxGroup("Vibrator 2"), Range(4, 10)] + public int Amplitude2 = 4; + [Button] + public void Vibrator_2Active() + { + if (Network == null) return; + SingleVirbator[] Virbators; + if (Hand == HandType.Left) + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(2, Duration2, Amplitude2), + new SingleVirbator() + }; + vibrationData = new VibrationData(Virbators); + } + else + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(), + new SingleVirbator(2, Duration2, Amplitude2), + }; + vibrationData = new VibrationData(Virbators); + } + Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData); + } + [Button] + public void BothActiveWithVibrator_1Parameters() + { + if (Network == null) return; + SingleVirbator[] Virbators; + if (Hand == HandType.Left) + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(3, Duration1, Amplitude1), + new SingleVirbator() + }; + vibrationData = new VibrationData(Virbators); + } + else + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(), + new SingleVirbator(3, Duration1, Amplitude1), + }; + vibrationData = new VibrationData(Virbators); + } + Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData); + } + + + // Start is called before the first frame update + void Start() + { + if (GameObject.Find("Network") == null && (UsingAndroidService || UsingNetwork)) + { + GameObject network = new GameObject("Network"); + network.AddComponent(); + Network = GameObject.Find("Network").GetComponent(); + } + else if (UsingAndroidService || UsingNetwork) + { + Network = GameObject.Find("Network").GetComponent(); + } + + _originQuaternionDic = new Dictionary(); + InitJoints(); + + if (string.IsNullOrEmpty(SendBackIP) || UsingAndroidService) + { + SendBackIP = "127.0.0.1"; + } + + var Virbators = new SingleVirbator[2] + { + new SingleVirbator(0, 0, 1), + new SingleVirbator(0, 0, 1) + }; + + vibrationData = new VibrationData(Virbators); + + if(UsingAndroidService) + { + CharacterName = "AndroidService"; + } + } + + private void InitJoints() + { + _originQuaternionDic.AddOrUpdate(Thumb1.name, Thumb1.localRotation); + _originQuaternionDic.AddOrUpdate(Thumb2.name, Thumb2.localRotation); + _originQuaternionDic.AddOrUpdate(Thumb3.name, Thumb3.localRotation); + + _originQuaternionDic.AddOrUpdate(Index1.name, Index1.localRotation); + _originQuaternionDic.AddOrUpdate(Index2.name, Index2.localRotation); + _originQuaternionDic.AddOrUpdate(Index3.name, Index3.localRotation); + + _originQuaternionDic.AddOrUpdate(Middle1.name, Middle1.localRotation); + _originQuaternionDic.AddOrUpdate(Middle2.name, Middle2.localRotation); + _originQuaternionDic.AddOrUpdate(Middle3.name, Middle3.localRotation); + + _originQuaternionDic.AddOrUpdate(Ring1.name, Ring1.localRotation); + _originQuaternionDic.AddOrUpdate(Ring2.name, Ring2.localRotation); + _originQuaternionDic.AddOrUpdate(Ring3.name, Ring3.localRotation); + + _originQuaternionDic.AddOrUpdate(Pinky1.name, Pinky1.localRotation); + _originQuaternionDic.AddOrUpdate(Pinky2.name, Pinky2.localRotation); + _originQuaternionDic.AddOrUpdate(Pinky3.name, Pinky3.localRotation); + + _originQuaternionDic.AddOrUpdate(Wrist.name, Wrist.localRotation); + } + + private void Rotate(Transform tran, float angle, Axis angleType) + { + if (!NeedRealTransfrom) return; + + float angleX = 0; + float angleY = 0; + float angleZ = 0; + + switch (angleType) + { + case Axis.x_n: + angleX = -angle; + break; + case Axis.y_n: + angleY = -angle; + break; + case Axis.z_n: + angleZ = -angle; + break; + case Axis.x: + angleX = angle; + break; + case Axis.y: + angleY = angle; + break; + case Axis.z: + angleZ = angle; + break; + } + + tran.Rotate(angleX, angleY, angleZ); + } + + private Vector3 ConvertAngleToVec3(Vector3 current, float angle, Axis angleType) + { + float angleX = 0; + float angleY = 0; + float angleZ = 0; + + switch (angleType) + { + case Axis.x_n: + angleX = -angle; + break; + case Axis.y_n: + angleY = -angle; + break; + case Axis.z_n: + angleZ = -angle; + break; + case Axis.x: + angleX = angle; + break; + case Axis.y: + angleY = angle; + break; + case Axis.z: + angleZ = angle; + break; + } + + return current + new Vector3(angleX, angleY, angleZ); + } + + private void ResetRotation(Transform trans) + { + if (_originQuaternionDic.TryGetValue(trans.name, out Quaternion rot)) + { + trans.localRotation = rot; + } + } + + public void GetVec3Value(Vector3[] value) + { + thumb1 = value[0]; + thumb2 = value[1]; + thumb3 = value[2]; + + index1 = value[3]; + index2 = value[4]; + index3 = value[5]; + + middle1 = value[6]; + middle2 = value[7]; + middle3 = value[8]; + + ring1 = value[9]; + ring2 = value[10]; + ring3 = value[11]; + + pinky1 = value[12]; + pinky2 = value[13]; + pinky3 = value[14]; + } + + // Update is called once per frame + void Update() + { + if (UsingNetwork || UsingAndroidService) + { + UpdateThumb(); + UpdateIndex(); + UpdateMiddle(); + UpdateRing(); + UpdatePinky(); + + UpdateWrist(); + UpdateController(); + } + } + + private void UpdateWrist() + { + if (HasIMU) + { + if (Hand == HandType.Left) + { + Quaternion quat_r = new Quaternion( + Network.Convert2Angle(CharacterName, "l26"),//x + Network.Convert2Angle(CharacterName, "l25"),//y + Network.Convert2Angle(CharacterName, "l27"),//z + Network.Convert2Angle(CharacterName, "l24"));//w + ResetRotation(Wrist); + quat_r = ConvertQuaternion(quat_r); + Wrist.rotation = quat_r; + } + else + { + Quaternion quat_r = new Quaternion(Network.Convert2Angle(CharacterName, "r26"), + Network.Convert2Angle(CharacterName, "r25"), + Network.Convert2Angle(CharacterName, "r27"), Network.Convert2Angle(CharacterName, "r24")); + ResetRotation(Wrist); + quat_r = ConvertQuaternion(quat_r); + Wrist.rotation = quat_r; + } + } + } + + private void UpdateController() + { + if (Hand == HandType.Left) + { + Joy_X = Network.Convert2Angle(CharacterName, "l_joyX"); + Joy_Y = Network.Convert2Angle(CharacterName, "l_joyY"); + Button_A = Network.Convert2Bool(CharacterName, "l_aButton"); + Button_B = Network.Convert2Bool(CharacterName, "l_bButton"); + Button_Joystick = Network.Convert2Bool(CharacterName, "l_joyButton"); + Button_Menu = Network.Convert2Bool(CharacterName, "l_menu"); + inputData.joyX = Joy_X; + inputData.joyY = Joy_Y; + inputData.aButton = Button_A; + inputData.bButton = Button_B; + inputData.joyButton = Button_Joystick; + inputData.menu = Button_Menu; + } + else + { + Joy_X = Network.Convert2Angle(CharacterName, "r_joyX"); + Joy_Y = Network.Convert2Angle(CharacterName, "r_joyY"); + Button_A = Network.Convert2Bool(CharacterName, "r_aButton"); + Button_B = Network.Convert2Bool(CharacterName, "r_bButton"); + Button_Joystick = Network.Convert2Bool(CharacterName, "r_joyButton"); + Button_Menu = Network.Convert2Bool(CharacterName, "r_menu"); + inputData.joyX = Joy_X; + inputData.joyY = Joy_Y; + inputData.aButton = Button_A; + inputData.bButton = Button_B; + inputData.joyButton = Button_Joystick; + inputData.menu = Button_Menu; + } + } + + //z轴朝上的右手坐标系 四元数 转换为 Y轴朝上的左手坐标系 四元数 + private Quaternion ConvertQuaternion(Quaternion quat) + { + Quaternion quat_r = new Quaternion(quat.x, quat.y, quat.z, quat.w); + quat_r = Quaternion.Euler(quat_r.eulerAngles.z, -quat_r.eulerAngles.x, quat_r.eulerAngles.y); + return quat_r; + } + + private void UpdateThumb() + { + if (NeedRealTransfrom) + { + ResetRotation(Thumb1); + ResetRotation(Thumb2); + ResetRotation(Thumb3); + } + if (Hand == HandType.Left) + { + var thumb3Pitch = Network.Convert2Angle(CharacterName, "l0"); + var thumb2Pitch = Network.Convert2Angle(CharacterName, "l1"); + var thumb1Pitch = Network.Convert2Angle(CharacterName, "l2") * coefficient + Thumb1Offset.y; + var thumb1Yaw = Network.Convert2Angle(CharacterName, "l3") + Thumb1Offset.z; + var thumb1Roll = Network.Convert2Angle(CharacterName, "l20") + Thumb1Offset.x; + + thumb3 = ConvertAngleToVec3(Vector3.zero, thumb3Pitch, Pitch); + thumb2 = ConvertAngleToVec3(Vector3.zero, thumb2Pitch, Pitch); + thumb1 = ConvertAngleToVec3(Vector3.zero, thumb1Pitch, Pitch); + thumb1 = ConvertAngleToVec3(thumb1, thumb1Yaw, Yaw); + thumb1 = ConvertAngleToVec3(thumb1, thumb1Roll, Roll); + + Rotate(Thumb3, thumb3Pitch, Pitch); + Rotate(Thumb2, thumb2Pitch, Pitch); + Rotate(Thumb1, thumb1Pitch, Pitch); + Rotate(Thumb1, thumb1Yaw, Yaw); + Rotate(Thumb1, thumb1Roll, Roll); + } + else + { + + var thumb3Pitch = Network.Convert2Angle(CharacterName, "r0"); + var thumb2Pitch = Network.Convert2Angle(CharacterName, "r1"); + var thumb1Pitch = Network.Convert2Angle(CharacterName, "r2") * coefficient + Thumb1Offset.y; + var thumb1Yaw = Network.Convert2Angle(CharacterName, "r3") + Thumb1Offset.z; + var thumb1Roll = Network.Convert2Angle(CharacterName, "r20") + Thumb1Offset.x; + + thumb3 = ConvertAngleToVec3(Vector3.zero, thumb3Pitch, Pitch); + thumb2 = ConvertAngleToVec3(Vector3.zero, thumb2Pitch, Pitch); + thumb1 = ConvertAngleToVec3(Vector3.zero, thumb1Pitch, Pitch); + thumb1 = ConvertAngleToVec3(thumb1, thumb1Yaw, Yaw); + thumb1 = ConvertAngleToVec3(thumb1, thumb1Roll, Roll); + + Rotate(Thumb3, thumb3Pitch, Pitch); + Rotate(Thumb2, thumb2Pitch, Pitch); + Rotate(Thumb1, thumb1Pitch, Pitch); + Rotate(Thumb1, thumb1Yaw, Yaw); + Rotate(Thumb1, thumb1Roll, Roll); + } + } + + private void UpdateIndex() + { + if (NeedRealTransfrom) + { + ResetRotation(Index1); + ResetRotation(Index2); + ResetRotation(Index3); + } + if (Hand == HandType.Left) + { + var index3Pitch = Network.Convert2Angle(CharacterName, "l4"); + var index2Pitch = Network.Convert2Angle(CharacterName, "l5"); + var index1Pitch = Network.Convert2Angle(CharacterName, "l6"); + var index1Yaw = Network.Convert2Angle(CharacterName, "l7"); + var index1Roll = Network.Convert2Angle(CharacterName, "l21"); + + index3 = ConvertAngleToVec3(Vector3.zero, index3Pitch, Pitch); + index2 = ConvertAngleToVec3(Vector3.zero, index2Pitch, Pitch); + index1 = ConvertAngleToVec3(Vector3.zero, index1Pitch, Pitch); + index1 = ConvertAngleToVec3(index1, index1Yaw, Yaw); + index1 = ConvertAngleToVec3(index1, index1Roll, Roll); + + Rotate(Index3, index3Pitch, Pitch); + Rotate(Index2, index2Pitch, Pitch); + Rotate(Index1, index1Pitch, Pitch); + Rotate(Index1, index1Yaw, Yaw); + Rotate(Index1, index1Roll, Roll); + } + else + { + var index3Pitch = Network.Convert2Angle(CharacterName, "r4"); + var index2Pitch = Network.Convert2Angle(CharacterName, "r5"); + var index1Pitch = Network.Convert2Angle(CharacterName, "r6"); + var index1Yaw = Network.Convert2Angle(CharacterName, "r7"); + var index1Roll = Network.Convert2Angle(CharacterName, "r21"); + + index3 = ConvertAngleToVec3(Vector3.zero, index3Pitch, Pitch); + index2 = ConvertAngleToVec3(Vector3.zero, index2Pitch, Pitch); + index1 = ConvertAngleToVec3(Vector3.zero, index1Pitch, Pitch); + index1 = ConvertAngleToVec3(index1, index1Yaw, Yaw); + index1 = ConvertAngleToVec3(index1, index1Roll, Roll); + + Rotate(Index3, index3Pitch, Pitch); + Rotate(Index2, index2Pitch, Pitch); + Rotate(Index1, index1Pitch, Pitch); + Rotate(Index1, index1Yaw, Yaw); + Rotate(Index1, index1Roll, Roll); + } + } + + private void UpdateMiddle() + { + if (NeedRealTransfrom) + { + ResetRotation(Middle1); + ResetRotation(Middle2); + ResetRotation(Middle3); + } + if (Hand == HandType.Left) + { + var middle3Pitch = Network.Convert2Angle(CharacterName, "l8"); + var middle2Pitch = Network.Convert2Angle(CharacterName, "l9"); + var middle1Pitch = Network.Convert2Angle(CharacterName, "l10"); + var middle1Yaw = Network.Convert2Angle(CharacterName, "l11"); + + middle3 = ConvertAngleToVec3(Vector3.zero, middle3Pitch, Pitch); + middle2 = ConvertAngleToVec3(Vector3.zero, middle2Pitch, Pitch); + middle1 = ConvertAngleToVec3(Vector3.zero, middle1Pitch, Pitch); + middle1 = ConvertAngleToVec3(middle1, middle1Yaw, Yaw); + + Rotate(Middle3, middle3Pitch, Pitch); + Rotate(Middle2, middle2Pitch, Pitch); + Rotate(Middle1, middle1Pitch, Pitch); + Rotate(Middle1, middle1Yaw, Yaw); + } + else + { + var middle3Pitch = Network.Convert2Angle(CharacterName, "r8"); + var middle2Pitch = Network.Convert2Angle(CharacterName, "r9"); + var middle1Pitch = Network.Convert2Angle(CharacterName, "r10"); + var middle1Yaw = Network.Convert2Angle(CharacterName, "r11"); + + middle3 = ConvertAngleToVec3(Vector3.zero, middle3Pitch, Pitch); + middle2 = ConvertAngleToVec3(Vector3.zero, middle2Pitch, Pitch); + middle1 = ConvertAngleToVec3(Vector3.zero, middle1Pitch, Pitch); + middle1 = ConvertAngleToVec3(middle1, middle1Yaw, Yaw); + + Rotate(Middle3, middle3Pitch, Pitch); + Rotate(Middle2, middle2Pitch, Pitch); + Rotate(Middle1, middle1Pitch, Pitch); + Rotate(Middle1, middle1Yaw, Yaw); + } + } + + private void UpdateRing() + { + if (NeedRealTransfrom) + { + ResetRotation(Ring1); + ResetRotation(Ring2); + ResetRotation(Ring3); + } + if (Hand == HandType.Left) + { + var ring3Pitch = Network.Convert2Angle(CharacterName, "l12"); + var ring2Pitch = Network.Convert2Angle(CharacterName, "l13"); + var ring1Pitch = Network.Convert2Angle(CharacterName, "l14"); + var ring1Yaw = Network.Convert2Angle(CharacterName, "l15"); + + ring3 = ConvertAngleToVec3(Vector3.zero, ring3Pitch, Pitch); + ring2 = ConvertAngleToVec3(Vector3.zero, ring2Pitch, Pitch); + ring1 = ConvertAngleToVec3(Vector3.zero, ring1Pitch, Pitch); + ring1 = ConvertAngleToVec3(ring1, ring1Yaw, Yaw); + + Rotate(Ring3, ring3Pitch, Pitch); + Rotate(Ring2, ring2Pitch, Pitch); + Rotate(Ring1, ring1Pitch, Pitch); + Rotate(Ring1, ring1Yaw, Yaw); + } + else + { + var ring3Pitch = Network.Convert2Angle(CharacterName, "r12"); + var ring2Pitch = Network.Convert2Angle(CharacterName, "r13"); + var ring1Pitch = Network.Convert2Angle(CharacterName, "r14"); + var ring1Yaw = Network.Convert2Angle(CharacterName, "r15"); + + ring3 = ConvertAngleToVec3(Vector3.zero, ring3Pitch, Pitch); + ring2 = ConvertAngleToVec3(Vector3.zero, ring2Pitch, Pitch); + ring1 = ConvertAngleToVec3(Vector3.zero, ring1Pitch, Pitch); + ring1 = ConvertAngleToVec3(ring1, ring1Yaw, Yaw); + + Rotate(Ring3, ring3Pitch, Pitch); + Rotate(Ring2, ring2Pitch, Pitch); + Rotate(Ring1, ring1Pitch, Pitch); + Rotate(Ring1, ring1Yaw, Yaw); + } + } + + private void UpdatePinky() + { + if (NeedRealTransfrom) + { + ResetRotation(Pinky1); + ResetRotation(Pinky2); + ResetRotation(Pinky3); + } + if (Hand == HandType.Left) + { + var pinky3Pitch = Network.Convert2Angle(CharacterName, "l16"); + var pinky2Pitch = Network.Convert2Angle(CharacterName, "l17"); + var pinky1Pitch = Network.Convert2Angle(CharacterName, "l18"); + var pinky1Yaw = Network.Convert2Angle(CharacterName, "l19"); + var pinky1Roll = Network.Convert2Angle(CharacterName, "l22"); + + pinky3 = ConvertAngleToVec3(Vector3.zero, pinky3Pitch, Pitch); + pinky2 = ConvertAngleToVec3(Vector3.zero, pinky2Pitch, Pitch); + pinky1 = ConvertAngleToVec3(Vector3.zero, pinky1Pitch, Pitch); + pinky1 = ConvertAngleToVec3(pinky1, pinky1Yaw, Yaw); + pinky1 = ConvertAngleToVec3(pinky1, pinky1Roll, Roll); + + Rotate(Pinky3, pinky3Pitch, Pitch); + Rotate(Pinky2, pinky2Pitch, Pitch); + Rotate(Pinky1, pinky1Pitch, Pitch); + Rotate(Pinky1, pinky1Yaw, Yaw); + Rotate(Pinky1, pinky1Roll, Roll); + } + else + { + var pinky3Pitch = Network.Convert2Angle(CharacterName, "r16"); + var pinky2Pitch = Network.Convert2Angle(CharacterName, "r17"); + var pinky1Pitch = Network.Convert2Angle(CharacterName, "r18"); + var pinky1Yaw = Network.Convert2Angle(CharacterName, "r19"); + var pinky1Roll = Network.Convert2Angle(CharacterName, "r22"); + + pinky3 = ConvertAngleToVec3(Vector3.zero, pinky3Pitch, Pitch); + pinky2 = ConvertAngleToVec3(Vector3.zero, pinky2Pitch, Pitch); + pinky1 = ConvertAngleToVec3(Vector3.zero, pinky1Pitch, Pitch); + pinky1 = ConvertAngleToVec3(pinky1, pinky1Yaw, Yaw); + pinky1 = ConvertAngleToVec3(pinky1, pinky1Roll, Roll); + + Rotate(Pinky3, pinky3Pitch, Pitch); + Rotate(Pinky2, pinky2Pitch, Pitch); + Rotate(Pinky1, pinky1Pitch, Pitch); + Rotate(Pinky1, pinky1Yaw, Yaw); + Rotate(Pinky1, pinky1Roll, Roll); + } + } + + public void ServiceVibrationControl(int VirbatorIndex = 1, int DurationSecond = 20, int Strength = 10) + { + if (Network == null || !UsingAndroidService) return; + + SingleVirbator[] Virbators; + if (Hand == HandType.Left) + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(VirbatorIndex, DurationSecond, Strength), + new SingleVirbator() + }; + vibrationData = new VibrationData(Virbators); + } + else + { + Virbators = new SingleVirbator[2] + { + new SingleVirbator(), + new SingleVirbator(VirbatorIndex, DurationSecond, Strength), + }; + vibrationData = new VibrationData(Virbators); + } + Network.SendVibrationMsg("AndroidService", "127.0.0.1", vibrationData); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs.meta b/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs.meta new file mode 100644 index 0000000..168a34f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4912e9bafca683489c72f3a27094c57 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs b/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs new file mode 100644 index 0000000..69d5f99 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs @@ -0,0 +1,35 @@ +//Struct InputData is a struct that contains all of the button, finger, and linear inputs. This is what's sent to the driver via the named pipe. +public struct InputData +{ + + public float joyX; //range: -1 -> 1 + public float joyY; //range: -1 -> 1 + public bool joyButton; + public bool trgButton; + public bool aButton; + public bool bButton; + public bool grab; + //public bool pinch; + public bool menu; + //public bool calibrate; + public bool trackpad_touch; + public float trgValue; //range: 0 -> 1 + + //constructor that uses a 1d array for flexion. + public InputData(float joyX, float joyY, bool joyButton, bool trgButton, + bool aButton, bool bButton, bool grab, bool pinch, bool menu, bool calibrate, float trgValue,bool trackpad_touch) + { + this.joyX = joyX; + this.joyY = joyY; + this.joyButton = joyButton; + this.trgButton = trgButton; + this.aButton = aButton; + this.bButton = bButton; + this.grab = grab; + //this.pinch = pinch; + this.menu = menu; + //this.calibrate = calibrate; + this.trgValue = trgValue; + this.trackpad_touch = trackpad_touch; + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs.meta b/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs.meta new file mode 100644 index 0000000..57c3701 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0dcc86f284979df4ead3842bec665562 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs b/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs new file mode 100644 index 0000000..4ea7b45 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs @@ -0,0 +1,207 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Net; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; +using UnityEngine; + +public class Network : MonoBehaviour +{ + + public int Port = 5555; + + private UdpSession _udpClient; + + private ConcurrentDictionary> _deviceReadMessages; + + private StreamWriter writer; + private string _txtPath; + void Start() + { + _txtPath = Application.dataPath + "stream.data"; + _deviceReadMessages = new ConcurrentDictionary>(); + _udpClient = new UdpSession(); + + _udpClient.Received += ReceiveMsg; + + _udpClient.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(Port)) + .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) + .Start(); + + Debug.Log("UDP Client Start!!"); + + } + + + private void WriteIntoTxt(string message) + { + FileInfo file = new FileInfo(_txtPath); + if (!file.Exists) + { + writer = file.CreateText(); + } + else + { + writer = file.AppendText(); + } + + writer.WriteLine(message); + writer.Flush(); + writer.Dispose(); + writer.Close(); + } + + private void ReceiveMsg(EndPoint endpoint, ByteBlock byteblock, IRequestInfo requestinfo) + { + string msg = Encoding.UTF8.GetString(byteblock.Buffer, 0, byteblock.Len); + Debug.Log(msg); + //WriteIntoTxt(msg); + JObject obj = JObject.Parse(msg); + var jps = obj.Properties(); + foreach (var jp in jps) + { + string role_name = jp.Name; + + JToken token = obj.GetValue(role_name); + JArray array = token["Parameter"] as JArray; + ConcurrentDictionary _deviceMsg = new ConcurrentDictionary(); + for (int i = 0; i < array.Count; i++) + { + JObject obj1 = array[i] as JObject; + string key = obj1.GetValue("Name").ToString(); + string value = obj1.GetValue("Value").ToString(); + _deviceMsg.TryAdd(key, value); + } + if (_deviceReadMessages.ContainsKey(role_name)) + { + _deviceReadMessages[role_name] = _deviceMsg; + } + else + { + _deviceReadMessages.TryAdd(role_name, _deviceMsg); + } + + } + //JToken token = obj.GetValue("Device1_"+Port); + //JArray array = token["Parameter"] as JArray; + //for (int i = 0; i < array.Count; i++) + //{ + // JObject obj1 = array[i] as JObject; + // string key = obj1.GetValue("Name").ToString(); + // string value = obj1.GetValue("Value").ToString(); + // _device1ReadMessages.AddOrUpdate(key, value); + //} + + //JToken token2 = obj.GetValue("Device2_"+Port); + //JArray array2 = token2["Parameter"] as JArray; + //for (int i = 0; i < array.Count; i++) + //{ + // JObject obj1 = array2[i] as JObject; + // string key = obj1.GetValue("Name").ToString(); + // string value = obj1.GetValue("Value").ToString(); + // _device2ReadMessages.AddOrUpdate(key, value); + //} + } + + // Update is called once per frame + void Update() + { + + } + + public float Convert2Angle(string role_name, string key) + { + float angle = 0; + if (!string.IsNullOrEmpty(role_name)) + { + if (!_deviceReadMessages.ContainsKey(role_name)) + { + return 0; + } + string str = _deviceReadMessages[role_name][key]; + + if (!string.IsNullOrEmpty(str)) + { + angle = Single.Parse(str); + } + } + return angle; + } + + public bool Convert2Bool(string role_name, string key) + { + bool flag = false; + if (!string.IsNullOrEmpty(role_name)) + { + if (!_deviceReadMessages.ContainsKey(role_name)) + { + return false; + } + string str = _deviceReadMessages[role_name][key]; + + if (!string.IsNullOrEmpty(str)) + { + flag = bool.Parse(str); + } + } + return flag; + } + + public void SendVibrationMsg(string RoleName, string IP, VibrationData data) + { + var json_role = new JObject(); + var json_one = new JObject(); + var parameterArrayLeft = new JArray(); + var parameterArrayRight = new JArray(); + + var _Lpara_active = new JObject(); + _Lpara_active.Add("Name", "Vibrators"); + _Lpara_active.Add("Value", data.Virbators[0].ActiveCommand); + + var _Lpara_duration = new JObject(); + _Lpara_duration.Add("Name", "Duration"); + _Lpara_duration.Add("Value", data.Virbators[0].Duration); + + var _Lpara_amplitude = new JObject(); + _Lpara_amplitude.Add("Name", "Amplitude"); + _Lpara_amplitude.Add("Value", data.Virbators[0].Amplitude); + + parameterArrayLeft.Add(_Lpara_active); + parameterArrayLeft.Add(_Lpara_duration); + parameterArrayLeft.Add(_Lpara_amplitude); + + var _Rpara_active = new JObject(); + _Rpara_active.Add("Name", "Vibrators"); + _Rpara_active.Add("Value", data.Virbators[1].ActiveCommand); + + var _Rpara_duration = new JObject(); + _Rpara_duration.Add("Name", "Duration"); + _Rpara_duration.Add("Value", data.Virbators[1].Duration); + + var _Rpara_amplitude = new JObject(); + _Rpara_amplitude.Add("Name", "Amplitude"); + _Rpara_amplitude.Add("Value", data.Virbators[1].Amplitude); + + parameterArrayRight.Add(_Rpara_active); + parameterArrayRight.Add(_Rpara_duration); + parameterArrayRight.Add(_Rpara_amplitude); + + json_one.Add("LeftHand", parameterArrayLeft); + json_one.Add("RightHand", parameterArrayRight); + json_role.Add(RoleName, json_one); + + Debug.Log(json_role.ToJson()); + _udpClient.Send(new IPEndPoint(IPAddress.Parse(IP), 8920), Encoding.UTF8.GetBytes(json_role.ToJson())); + } + + private void OnDestroy() + { + _udpClient.Received -= ReceiveMsg; + _udpClient.Stop(); + _udpClient.Dispose(); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs.meta b/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs.meta new file mode 100644 index 0000000..223ab1e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09a3acc4e9487ff42a0d425e4f64d16c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs b/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs new file mode 100644 index 0000000..ceec53f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs @@ -0,0 +1,33 @@ + +public struct SingleVirbator +{ + public int ActiveCommand; + public int Duration; + public int Amplitude; + + public SingleVirbator(int command = 1, int duration = 0, int amplitude = 4) + { + command = command < 1 ? 1 : command > 3 ? 3 : command; + duration = duration < 0 ? 0 : duration; + amplitude = amplitude < 4 ? 4 : amplitude > 10 ? 10 : amplitude; + + ActiveCommand = command; + Duration = duration; + Amplitude = amplitude; + } +} + +public class VibrationData +{ + public SingleVirbator[] Virbators = new SingleVirbator[2]; + + public VibrationData(SingleVirbator[] virbators) + { + if (virbators.Length != 2) return; + + for (int i = 0; i < virbators.Length; i++) + { + Virbators[i] = virbators[i]; + } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs.meta b/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs.meta new file mode 100644 index 0000000..0043e5c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 75c4983c107b62942888902b38f76ba6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd.meta new file mode 100644 index 0000000..f995d7c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cdf9bacc33468244686934a49aa9a620 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket.meta new file mode 100644 index 0000000..a2161dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1102a8bb1c06f94880e4da841d2732a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core.meta new file mode 100644 index 0000000..38311fd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b771b2c214473934a9045eb277704b07 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager.meta new file mode 100644 index 0000000..12d919d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fb3f51f059e0164419ceba82a86e529d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs new file mode 100644 index 0000000..aaf3cae --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs @@ -0,0 +1,1309 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 字节块流 + /// + [DebuggerDisplay("Len={Len},Pos={Pos},Capacity={Capacity}")] + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public sealed partial class ByteBlock : Stream, IWrite + { + private static float m_ratio = 1.5f; + private readonly bool m_needDis; + private byte[] m_buffer; + private int m_dis = 1; + private bool m_holding; + private long m_length; + private long m_position; + private bool m_using; + + /// + /// 构造函数 + /// + /// + /// + public ByteBlock(int byteSize = 1024 * 64, bool equalSize = false) + { + m_needDis = true; + m_buffer = BytePool.Default.GetByteCore(byteSize, equalSize); + m_using = true; + } + + /// + /// 实例化一个已知内存的对象。且该内存不会被回收。 + /// + /// + public ByteBlock(byte[] bytes) + { + m_buffer = bytes ?? throw new ArgumentNullException(nameof(bytes)); + m_length = bytes.Length; + m_using = true; + } + + /// + /// 扩容增长比,默认为1.5, + /// min:1.5 + /// + public static float Ratio + { + get => m_ratio; + set + { + if (value < 1.5) + { + value = 1.5f; + } + m_ratio = value; + } + } + + /// + /// 字节实例 + /// + public byte[] Buffer => m_buffer; + + /// + /// 仅当内存块可用,且>0时为True。 + /// + public override bool CanRead => m_using && CanReadLen > 0; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public int CanReadLen => Len - Pos; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public long CanReadLength => m_length - m_position; + + /// + /// 支持查找 + /// + public override bool CanSeek => m_using; + + /// + /// 可写入 + /// + public override bool CanWrite => m_using; + + /// + /// 容量 + /// + public int Capacity => m_buffer.Length; + + /// + /// 空闲长度,准确掌握该值,可以避免内存扩展,计算为的差值。 + /// + public int FreeLength => Capacity - Pos; + + /// + /// 表示持续性持有,为True时,Dispose将调用无效。 + /// + public bool Holding => m_holding; + + /// + /// Int真实长度 + /// + public int Len => (int)m_length; + + /// + /// 真实长度 + /// + public override long Length => m_length; + + /// + /// int型流位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 流位置 + /// + public override long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 使用状态 + /// + public bool Using => m_using; + + /// + /// 直接完全释放,游离该对象,然后等待GC + /// + public void AbsoluteDispose() + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + Dis(); + } + } + + /// + /// 清空所有内存数据 + /// + /// 内存块已释放 + public void Clear() + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + Array.Clear(m_buffer, 0, m_buffer.Length); + } + + /// + /// 无实际效果 + /// + //IntelligentCoder.AsyncMethodIgnore] + public override void Flush() + { + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + int len = m_length - m_position > length ? length : CanReadLen; + Array.Copy(m_buffer, m_position, buffer, offset, len); + m_position += len; + return len; + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + public int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// 读取数据,然后递增Pos + /// + + /// + /// + /// + public int Read(out byte[] buffer, int length) + { + buffer = new byte[length]; + return Read(buffer, 0, buffer.Length); + } + + /// + /// 从当前流位置读取一个值 + /// + public override int ReadByte() + { + byte value = m_buffer[m_position]; + m_position++; + return value; + } + + /// + /// 将内存块初始化到刚申请的状态。 + /// 仅仅重置属性。 + /// + /// 内存块已释放 + public void Reset() + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + m_position = 0; + m_length = 0; + } + + /// + /// 设置流位置 + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + switch (origin) + { + case SeekOrigin.Begin: + m_position = offset; + break; + + case SeekOrigin.Current: + m_position += offset; + break; + + case SeekOrigin.End: + m_position = m_length + offset; + break; + } + return m_position; + } + + /// + /// 移动游标 + /// + /// + /// + public ByteBlock Seek(int position) + { + Position = position; + return this; + } + + /// + /// 设置游标到末位 + /// + /// + public ByteBlock SeekToEnd() + { + Position = Length; + return this; + } + + /// + /// 设置游标到首位 + /// + /// + public ByteBlock SeekToStart() + { + Position = 0; + return this; + } + + /// + /// 重新设置容量 + /// + /// 新尺寸 + /// 是否保留元数据 + /// + public void SetCapacity(int size, bool retainedData = false) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + byte[] bytes = new byte[size]; + + if (retainedData) + { + Array.Copy(m_buffer, 0, bytes, 0, m_buffer.Length); + } + if (m_needDis) + { + BytePool.Default.Recycle(m_buffer); + } + m_buffer = bytes; + } + + /// + /// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。 + /// 当为False时,会自动调用Dispose。 + /// + /// + /// + public void SetHolding(bool holding) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + m_holding = holding; + if (!holding) + { + Dispose(); + } + } + + /// + /// 设置实际长度 + /// + /// + /// + public override void SetLength(long value) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (value > m_buffer.Length) + { + throw new Exception("设置值超出容量"); + } + m_length = value; + } + + /// + /// 从指定位置转化到指定长度的有效内存 + /// + /// + /// + /// + public byte[] ToArray(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + byte[] buffer = new byte[length]; + Array.Copy(m_buffer, offset, buffer, 0, buffer.Length); + return buffer; + } + + /// + /// 转换为有效内存 + /// + /// + public byte[] ToArray() + { + return ToArray(0, Len); + } + + /// + /// 从指定位置转化到有效内存 + /// + + /// + /// + /// + public byte[] ToArray(int offset) + { + return ToArray(offset, Len - offset); + } + + /// + /// 转换为UTF-8字符 + /// + /// + public override string ToString() + { + return ToString(0, Len); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// 长度 + /// + public string ToString(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + return Encoding.UTF8.GetString(m_buffer, offset, length); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// + public string ToString(int offset) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + return Encoding.UTF8.GetString(m_buffer, offset, Len - offset); + } + + /// + /// 写入 + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + if (count == 0) + { + return; + } + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (m_buffer.Length - m_position < count) + { + int need = m_buffer.Length + count - ((int)(m_buffer.Length - m_position)); + int lend = m_buffer.Length; + while (need > lend) + { + lend = (int)(lend * m_ratio); + } + SetCapacity(lend, true); + } + Array.Copy(buffer, offset, m_buffer, m_position, count); + m_position += count; + m_length = Math.Max(m_position, m_length); + } + + /// + /// + /// + /// + /// + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 释放当前内存到指定内存池 + /// + /// + public void Dispose(BytePool bytePool) + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + GC.SuppressFinalize(this); + bytePool.Recycle(m_buffer); + Dis(); + } + } + } + + /// + /// + /// + /// + protected override sealed void Dispose(bool disposing) + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + GC.SuppressFinalize(this); + BytePool.Default.Recycle(m_buffer); + Dis(); + } + } + + base.Dispose(disposing); + } + + private void Dis() + { + m_holding = false; + m_using = false; + m_position = 0; + m_length = 0; + m_buffer = null; + } + + #region BytesPackage + + /// + /// 从当前流位置读取一个独立的数组包 + /// + public byte[] ReadBytesPackage() + { + byte status = (byte)ReadByte(); + if (status == 0) + { + return null; + } + int length = ReadInt32(); + byte[] data = new byte[length]; + Array.Copy(Buffer, Pos, data, 0, length); + Pos += length; + return data; + } + + /// + /// 尝试获取数据包信息,方便从Buffer操作数据 + /// + /// + /// + /// + public bool TryReadBytesPackageInfo(out int pos, out int len) + { + byte status = (byte)ReadByte(); + if (status == 0) + { + pos = 0; + len = 0; + return false; + } + len = ReadInt32(); + pos = Pos; + return true; + } + + /// + /// 写入一个独立的数组包,值可以为null。 + /// + /// + /// + /// + public ByteBlock WriteBytesPackage(byte[] value, int offset, int length) + { + if (value == null) + { + Write((byte)0); + } + else + { + Write((byte)1); + Write(length); + Write(value, offset, length); + } + return this; + } + + /// + /// 写入一个独立的数组包。值可以为null。 + /// + /// + public ByteBlock WriteBytesPackage(byte[] value) + { + if (value == null) + { + return WriteBytesPackage(value, 0, 0); + } + return WriteBytesPackage(value, 0, value.Length); + } + + #endregion BytesPackage + + #region Int32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public int ReadInt32(bool? bigEndian = null) + { + int value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt32(Buffer, Pos); break; + } + m_position += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(int value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int32 + + #region Int16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public short ReadInt16(bool? bigEndian = null) + { + short value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(short value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int16 + + #region Int64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public long ReadInt64(bool? bigEndian = null) + { + long value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(long value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int64 + + #region Boolean + + /// + /// 从当前流位置读取一个值 + /// + public bool ReadBoolean() + { + bool value = TouchSocketBitConverter.Default.ToBoolean(Buffer, Pos); + Pos += 1; + return value; + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(bool value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value)); + return this; + } + + #endregion Boolean + + #region Byte + + /// + /// 写入值 + /// + /// + /// + public ByteBlock Write(byte value) + { + Write(new byte[] { value }, 0, 1); + return this; + } + + #endregion Byte + + #region String + + /// + /// 从当前流位置读取一个值 + /// + public string ReadString() + { + int len = this.ReadInt32(); + if (len < 0) + { + return null; + } + else + { + string str = Encoding.UTF8.GetString(Buffer, Pos, len); + Pos += len; + return str; + } + } + + /// + /// 写入值。值可以为null,或者空。 + /// 注意:该操作不具备通用性,读取时必须使用ReadString。或者得先做出判断,由默认端序的int32值标识,具体如下: + /// + /// 小于0,表示字符串为null + /// 等于0,表示字符串为"" + /// 大于0,表示字符串在utf-8编码下的字节长度。 + /// + /// + /// + public ByteBlock Write(string value) + { + if (value == null) + { + Write(-1); + } + else + { + byte[] buffer = Encoding.UTF8.GetBytes(value); + Write(buffer.Length); + Write(buffer); + } + return this; + } + + /// + /// 写入值。值必须为有效值。可通用解析。 + /// + /// + /// + public ByteBlock WriteString(string value, Encoding encoding = null) + { + Write((encoding ?? Encoding.UTF8).GetBytes(value)); + return this; + } + + #endregion String + + #region Char + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public char ReadChar(bool? bigEndian = null) + { + char value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToChar(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToChar(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToChar(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(char value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Char + + #region Double + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public double ReadDouble(bool? bigEndian = null) + { + double value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToDouble(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToDouble(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToDouble(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(double value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Double + + #region Float + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public float ReadFloat(bool? bigEndian = null) + { + float value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToSingle(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToSingle(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToSingle(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(float value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Float + + #region UInt16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ushort ReadUInt16(bool? bigEndian = null) + { + ushort value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(ushort value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt16 + + #region UInt32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public uint ReadUInt32(bool? bigEndian = null) + { + uint value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt32(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(uint value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt32 + + #region UInt64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ulong ReadUInt64(bool? bigEndian = null) + { + ulong value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(ulong value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt64 + + #region Null + + /// + /// 从当前流位置读取一个标识值,判断是否为null。 + /// + public bool ReadIsNull() + { + var status = ReadByte(); + if (status == 0) + { + return true; + } + else if (status == 1) + { + return false; + } + else + { + throw new Exception("标识既非Null,也非NotNull,可能是流位置发生了错误。"); + } + } + + /// + /// 判断该值是否为Null,然后写入标识值 + /// + public ByteBlock WriteIsNull(T t) where T : class + { + if (t == null) + { + WriteNull(); + } + else + { + WriteNotNull(); + } + return this; + } + + /// + /// 写入一个标识非Null值 + /// + public ByteBlock WriteNotNull() + { + Write((byte)1); + return this; + } + + /// + /// 写入一个标识Null值 + /// + public ByteBlock WriteNull() + { + Write((byte)0); + return this; + } + + #endregion Null + + #region Package + + /// + /// 读取一个指定类型的包 + /// + /// + /// + public TPackage ReadPackage() where TPackage : class, IPackage, new() + { + if (ReadIsNull()) + { + return default; + } + else + { + TPackage package = new TPackage(); + package.Unpackage(this); + return package; + } + } + + /// + /// 以包进行写入。允许null值。 + /// 读取时调用,解包。或者先判断,然后自行解包。 + /// + /// + /// + /// + public ByteBlock WritePackage(TPackage package) where TPackage : class, IPackage + { + WriteIsNull(package); + if (package != null) + { + package.Package(this); + } + + return this; + } + + #endregion Package + + #region DateTime + + /// + /// 从当前流位置读取一个值 + /// + public DateTime ReadDateTime() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return DateTime.FromBinary(value); + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(DateTime value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.ToBinary())); + return this; + } + + #endregion DateTime + + #region TimeSpan + + /// + /// 从当前流位置读取一个值 + /// + public TimeSpan ReadTimeSpan() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return TimeSpan.FromTicks(value); + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(TimeSpan value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.Ticks)); + return this; + } + + #endregion TimeSpan + + #region Object + + /// + /// 从当前流位置读取一个泛型值 + /// + /// + /// + /// + public T ReadObject(SerializationType serializationType = SerializationType.FastBinary) + { + int length = ReadInt32(); + + if (length == 0) + { + return default; + } + + T obj; + + switch (serializationType) + { + case SerializationType.FastBinary: + { + obj = SerializeConvert.FastBinaryDeserialize(Buffer, Pos); + } + break; + + case SerializationType.Json: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.JsonDeserializeFromString(jsonString); + } + break; + + case SerializationType.Xml: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.XmlDeserializeFromString(jsonString); + } + break; + + case SerializationType.SystemBinary: + { + obj = SerializeConvert.BinaryDeserialize(Buffer, Pos, length); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Pos += length; + return obj; + } + + /// + /// 写入值 + /// + /// + /// + public ByteBlock WriteObject(object value, SerializationType serializationType = SerializationType.FastBinary) + { + if (value == null) + { + Write(0); + return this; + } + byte[] data; + switch (serializationType) + { + case SerializationType.FastBinary: + { + data = SerializeConvert.FastBinarySerialize(value); + } + break; + + case SerializationType.Json: + { + data = SerializeConvert.JsonSerializeToBytes(value); + } + break; + + case SerializationType.Xml: + { + data = Encoding.UTF8.GetBytes(SerializeConvert.XmlSerializeToString(value)); + } + break; + + case SerializationType.SystemBinary: + { + data = SerializeConvert.BinarySerialize(value); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Write(data.Length); + Write(data); + return this; + } + + #endregion Object + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs.meta new file mode 100644 index 0000000..f3beac8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e025222c673874469ee491627182d5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs new file mode 100644 index 0000000..76783d2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs @@ -0,0 +1,438 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 内存池 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class BytePool + { + private readonly ConcurrentDictionary bytesDictionary = new ConcurrentDictionary(); + private readonly Timer m_timer; + private long m_fullSize; + private long m_maxSize; + + static BytePool() + { + Default = new BytePool(); + } + + /// + /// 内存池 + /// + public BytePool() + { + m_timer = new Timer((o) => + { + Clear(); + }, null, 1000 * 60 * 60, 1000 * 60 * 60); + KeyCapacity = 100; + AutoZero = false; + m_maxSize = 1024 * 1024 * 512; + SetBlockSize(1024, 1024 * 1024 * 20); + AddSizeKey(10240); + } + + /// + /// 默认的内存池实例 + /// + public static BytePool Default { get; } + + /// + /// 回收内存时,自动归零 + /// + public bool AutoZero { get; set; } + + /// + /// 键容量 + /// + public int KeyCapacity { get; set; } + + /// + /// 单个块最大值 + /// + public int MaxBlockSize { get; private set; } + + /// + /// 允许的内存池最大值 + /// + public long MaxSize + { + get => m_maxSize; + set + { + if (value < 1024) + { + value = 1024; + } + m_maxSize = value; + } + } + + /// + /// 单个块最小值 + /// + public int MinBlockSize { get; private set; } + + /// + /// 添加尺寸键 + /// + /// + /// + public bool AddSizeKey(int byteSize) + { + if (bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize))) + { + return true; + } + return false; + } + + /// + /// 清理 + /// + public void Clear() + { + bytesDictionary.Clear(); + GC.Collect(); + } + + /// + /// 确定是否包含指定尺寸键 + /// + /// + /// + public bool ContainsSizeKey(int byteSize) + { + return bytesDictionary.ContainsKey(byteSize); + } + + /// + /// 获取所以内存键 + /// + /// + public long[] GetAllSizeKeys() + { + return bytesDictionary.Keys.ToArray(); + } + + /// + /// 获取ByteBlock + /// + /// 长度 + /// 要求长度相同 + /// + public ByteBlock GetByteBlock(int byteSize, bool equalSize) + { + return new ByteBlock(byteSize, equalSize); + } + + /// + /// 获取ByteBlock + /// + /// + /// + public ByteBlock GetByteBlock(int byteSize) + { + return new ByteBlock(byteSize, false); + } + + /// + /// 获取内存核心。获取的核心可以不用归还。 + /// 如果要调用归还,切记不要有持久性引用。 + /// + /// + /// + /// + public byte[] GetByteCore(int byteSize, bool equalSize = false) + { + BytesQueue bytesCollection; + if (equalSize) + { + //等长 + if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) + { + if (bytesCollection.TryGet(out byte[] bytes)) + { + m_fullSize -= byteSize; + return bytes; + } + } + else + { + CheckKeyCapacity(byteSize); + } + return new byte[byteSize]; + } + else + { + //byteSize = HitSize(byteSize); + //byteSize = byteSize; + //搜索已创建集合 + if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) + { + if (bytesCollection.TryGet(out byte[] bytes)) + { + m_fullSize -= byteSize; + return bytes; + } + } + else + { + CheckKeyCapacity(byteSize); + } + return new byte[byteSize]; + } + } + + /// + /// 获取内存池容量 + /// + /// + public long GetPoolSize() + { + long size = 0; + foreach (var item in bytesDictionary.Values) + { + size += item.FullSize; + } + return size; + } + + /// + /// 获取ValueByteBlock + /// + /// + /// + /// + //[IntelligentCoder.AsyncMethodIgnore] + public ValueByteBlock GetValueByteBlock(int byteSize, bool equalSize) + { + return new ValueByteBlock(byteSize, equalSize); + } + + /// + /// 获取ValueByteBlock + /// + /// + /// + //[IntelligentCoder.AsyncMethodIgnore] + public ValueByteBlock GetValueByteBlock(int byteSize) + { + return new ValueByteBlock(byteSize, false); + } + + /// + /// 回收内存核心。 + /// 注意:回收的内存,必须百分百确定该对象没有再被其他引用。不然这属于危险操作。 + /// + /// + public void Recycle(byte[] bytes) + { + if (bytes == null || bytes.Length > MaxBlockSize || bytes.Length < MinBlockSize) + { + return; + } + if (m_maxSize > m_fullSize) + { + if (bytesDictionary.TryGetValue(bytes.Length, out BytesQueue bytesQueue)) + { + if (AutoZero) + { + Array.Clear(bytes, 0, bytes.Length); + } + m_fullSize += bytes.Length; + bytesQueue.Add(bytes); + } + } + else + { + long size = 0; + foreach (var collection in bytesDictionary.Values) + { + size += collection.FullSize; + } + m_fullSize = size; + } + } + + /// + /// 移除尺寸键 + /// + /// + /// + public bool RemoveSizeKey(int byteSize) + { + if (bytesDictionary.TryRemove(byteSize, out BytesQueue queue)) + { + queue.Clear(); + return true; + } + return false; + } + + /// + /// 设置内存块参数 + /// + /// + /// + public void SetBlockSize(int minBlockSize, int maxBlockSize) + { + this.MaxBlockSize = maxBlockSize; + this.MinBlockSize = minBlockSize; + bytesDictionary.Clear(); + } + + private void CheckKeyCapacity(int byteSize) + { + if (byteSize < MinBlockSize || byteSize > MaxBlockSize) + { + return; + } + if (bytesDictionary.Count < KeyCapacity) + { + bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize)); + } + else + { + List bytesQueues = bytesDictionary.Values.ToList(); + bytesQueues.Sort((x, y) => { return x.m_referenced > y.m_referenced ? -1 : 1; }); + for (int i = (int)(bytesQueues.Count * 0.2); i < bytesQueues.Count; i++) + { + if (bytesDictionary.TryRemove(bytesQueues[i].m_size, out BytesQueue queue)) + { + queue.Clear(); + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int HitSize(int num) + { + if (num < MinBlockSize) + { + num = MinBlockSize; + } + + if (num <= 10240)//10k + { + return 10240; + } + else if (num <= 65536)//64k + { + return 65536; + } + else if (num <= 102400)//100k + { + return 102400; + } + else if (num <= 524288) //512k + { + return 524288; + } + else if (num <= 1048576)//1Mb + { + return 1048576; + } + else if (num <= 1048576 * 2)//2Mb + { + return 1048576 * 2; + } + else if (num <= 1048576 * 3)//3Mb + { + return 1048576 * 3; + } + else if (num <= 1048576 * 4)//4Mb + { + return 1048576 * 4; + } + else if (num <= 1048576 * 5)//5Mb + { + return 1048576 * 5; + } + else if (num <= 1048576 * 6)//6Mb + { + return 1048576 * 6; + } + else if (num <= 1048576 * 7)//7Mb + { + return 1048576 * 7; + } + else if (num <= 1048576 * 8)//8Mb + { + return 1048576 * 8; + } + else if (num <= 1048576 * 9)//9Mb + { + return 1048576 * 9; + } + else if (num <= 10485760)//10Mb + { + return 10485760; + } + else if (num <= 1024 * 1024 * 12)//12Mb + { + return 1024 * 1024 * 12; + } + else if (num <= 1024 * 1024 * 15)//15Mb + { + return 1024 * 1024 * 15; + } + else if (num <= 1024 * 1024 * 18)//18Mb + { + return 1024 * 1024 * 18; + } + else if (num <= 1024 * 1024 * 20)//20Mb + { + return 1024 * 1024 * 20; + } + else if (num <= 1024 * 1024 * 30)//30Mb + { + return 1024 * 1024 * 30; + } + else if (num <= 1024 * 1024 * 40)//40Mb + { + return 1024 * 1024 * 40; + } + else if (num <= 1024 * 1024 * 50)//50Mb + { + return 1024 * 1024 * 50; + } + else if (num <= 1024 * 1024 * 100)//100Mb + { + return 1024 * 1024 * 100; + } + else if (num <= 1024 * 1024 * 500)//500Mb + { + return 1024 * 1024 * 500; + } + else if (num <= 1024 * 1024 * 1024)//1Gb + { + return 1024 * 1024 * 1024; + } + else + { + return num; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs.meta new file mode 100644 index 0000000..630754e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0213f3d33332ec4894a79908796fd7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs new file mode 100644 index 0000000..f231f10 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// 字节块集合 + /// + [DebuggerDisplay("Count = {bytesQueue.Count}")] + internal class BytesQueue: ConcurrentStack + { + internal int m_size; + + internal BytesQueue(int size) + { + m_size = size; + } + + /// + /// 占用空间 + /// + public long FullSize => m_size * this.Count; + + internal long m_referenced; + + /// + /// 获取当前实例中的空闲的Block + /// + /// + public bool TryGet(out byte[] bytes) + { + m_referenced++; + return base.TryPop(out bytes); + } + + /// + /// 向当前集合添加Block + /// + /// + public void Add(byte[] bytes) + { + base.Push(bytes); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs.meta new file mode 100644 index 0000000..782f680 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48fa07724e84cff4b9fefcdc297de2cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs new file mode 100644 index 0000000..88e84b8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs @@ -0,0 +1,1249 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 字节块流 + /// + [DebuggerDisplay("Len={Len},Pos={Pos},Capacity={Capacity}")] + public ref partial struct ValueByteBlock + { + private static float m_ratio = 1.5f; + private readonly bool m_needDis; + private byte[] m_buffer; + private int m_dis; + private bool m_holding; + private long m_length; + private long m_position; + private bool m_using; + + /// + /// 构造函数 + /// + /// + /// + public ValueByteBlock(int byteSize = 1024 * 64, bool equalSize = false) + { + m_dis = 1; + m_needDis = true; + m_buffer = BytePool.Default.GetByteCore(byteSize, equalSize); + m_using = true; + m_length = 0; + m_holding = false; + m_position = 0; + } + + /// + /// 实例化一个已知内存的对象。且该内存不会被回收。 + /// + /// + public ValueByteBlock(byte[] bytes) + { + m_dis = 0; + m_needDis = false; + m_buffer = bytes ?? throw new ArgumentNullException(nameof(bytes)); + m_length = bytes.Length; + m_using = true; + m_length = 0; + m_holding = false; + m_position = 0; + } + + /// + /// 扩容增长比,默认为1.5, + /// min:1.5 + /// + public static float Ratio + { + get => m_ratio; + set + { + if (value < 1.5) + { + value = 1.5f; + } + m_ratio = value; + } + } + + /// + /// 字节实例 + /// + public byte[] Buffer => m_buffer; + + /// + /// 仅当内存块可用,且>0时为True。 + /// + public bool CanRead => m_using && CanReadLen > 0; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public int CanReadLen => Len - Pos; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public long CanReadLength => m_length - m_position; + + /// + /// 支持查找 + /// + public bool CanSeek => m_using; + + /// + /// 可写入 + /// + public bool CanWrite => m_using; + + /// + /// 容量 + /// + public int Capacity => m_buffer.Length; + + /// + /// 空闲长度,准确掌握该值,可以避免内存扩展,计算为的差值。 + /// + public int FreeLength => Capacity - Pos; + + /// + /// 表示持续性持有,为True时,Dispose将调用无效。 + /// + public bool Holding => m_holding; + + /// + /// Int真实长度 + /// + public int Len => (int)m_length; + + /// + /// 真实长度 + /// + public long Length => m_length; + + /// + /// int型流位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 流位置 + /// + public long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 使用状态 + /// + public bool Using => m_using; + + /// + /// 创建一个来自于内存池的成员。 + /// + /// + /// + /// + public static ValueByteBlock Create(int byteSize = 1024 * 64, bool equalSize = false) + { + return new ValueByteBlock(byteSize, equalSize); + } + + /// + /// 直接完全释放,游离该对象,然后等待GC + /// + public void AbsoluteDispose() + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + Dis(); + } + } + + /// + /// 清空所有内存数据 + /// + /// 内存块已释放 + public void Clear() + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + Array.Clear(m_buffer, 0, m_buffer.Length); + } + + /// + /// + /// + public void Dispose() + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + BytePool.Default.Recycle(m_buffer); + Dis(); + } + } + } + + /// + /// 释放当前内存到指定内存池 + /// + /// + public void Dispose(BytePool bytePool) + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + bytePool.Recycle(m_buffer); + Dis(); + } + } + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + /// + /// + /// + public int Read(byte[] buffer, int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + int len = m_length - m_position > length ? length : CanReadLen; + Array.Copy(m_buffer, m_position, buffer, offset, len); + m_position += len; + return len; + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + public int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// 读取数据,然后递增Pos + /// + + /// + /// + /// + public int Read(out byte[] buffer, int length) + { + buffer = new byte[length]; + return Read(buffer, 0, buffer.Length); + } + + /// + /// 从当前流位置读取一个值 + /// + public int ReadByte() + { + byte value = m_buffer[m_position]; + m_position++; + return value; + } + + /// + /// 将内存块初始化到刚申请的状态。 + /// 仅仅重置属性。 + /// + /// 内存块已释放 + public void Reset() + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + m_position = 0; + m_length = 0; + } + + /// + /// 设置流位置 + /// + /// + /// + /// + /// + public long Seek(long offset, SeekOrigin origin) + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + switch (origin) + { + case SeekOrigin.Begin: + m_position = offset; + break; + + case SeekOrigin.Current: + m_position += offset; + break; + + case SeekOrigin.End: + m_position = m_length + offset; + break; + } + return m_position; + } + + /// + /// 移动游标 + /// + /// + /// + public void Seek(int position) + { + Position = position; + } + + /// + /// 设置游标到末位 + /// + /// + public void SeekToEnd() + { + Position = Length; + } + + /// + /// 设置游标到首位 + /// + /// + public void SeekToStart() + { + Position = 0; + } + + /// + /// 重新设置容量 + /// + /// 新尺寸 + /// 是否保留元数据 + /// + public void SetCapacity(int size, bool retainedData = false) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + byte[] bytes = new byte[size]; + + if (retainedData) + { + Array.Copy(m_buffer, 0, bytes, 0, m_buffer.Length); + } + if (m_needDis) + { + BytePool.Default.Recycle(m_buffer); + } + m_buffer = bytes; + } + + /// + /// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。 + /// 当为False时,会自动调用Dispose。 + /// + /// + /// + public void SetHolding(bool holding) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + m_holding = holding; + if (!holding) + { + Dispose(); + } + } + + /// + /// 设置实际长度 + /// + /// + /// + public void SetLength(long value) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + if (value > m_buffer.Length) + { + throw new Exception("设置值超出容量"); + } + m_length = value; + } + + /// + /// 从指定位置转化到指定长度的有效内存 + /// + /// + /// + /// + public byte[] ToArray(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + byte[] buffer = new byte[length]; + Array.Copy(m_buffer, offset, buffer, 0, buffer.Length); + return buffer; + } + + /// + /// 转换为有效内存 + /// + /// + public byte[] ToArray() + { + return ToArray(0, Len); + } + + /// + /// 从指定位置转化到有效内存 + /// + /// + /// + /// + public byte[] ToArray(int offset) + { + return ToArray(offset, Len - offset); + } + + /// + /// 转换为UTF-8字符 + /// + /// + public override string ToString() + { + return ToString(0, Len); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// 长度 + /// + public string ToString(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + return Encoding.UTF8.GetString(m_buffer, offset, length); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// + public string ToString(int offset) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + return Encoding.UTF8.GetString(m_buffer, offset, Len - offset); + } + + /// + /// 写入 + /// + /// + /// + /// + /// + public void Write(byte[] buffer, int offset, int count) + { + if (count == 0) + { + return; + } + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + if (m_buffer.Length - m_position < count) + { + int need = m_buffer.Length + count - ((int)(m_buffer.Length - m_position)); + int lend = m_buffer.Length; + while (need > lend) + { + lend = (int)(lend * m_ratio); + } + SetCapacity(lend, true); + } + Array.Copy(buffer, offset, m_buffer, m_position, count); + m_position += count; + m_length = Math.Max(m_position, m_length); + } + + /// + /// + /// + /// + /// + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + private void Dis() + { + m_holding = false; + m_using = false; + m_position = 0; + m_length = 0; + m_buffer = null; + } + + #region BytesPackage + + /// + /// 从当前流位置读取一个独立的数组包 + /// + public byte[] ReadBytesPackage() + { + byte status = (byte)ReadByte(); + if (status == 0) + { + return null; + } + int length = ReadInt32(); + byte[] data = new byte[length]; + Array.Copy(Buffer, Pos, data, 0, length); + Pos += length; + return data; + } + + /// + /// 尝试获取数据包信息,方便从Buffer操作数据 + /// + /// + /// + /// + public bool TryReadBytesPackageInfo(out int pos, out int len) + { + byte status = (byte)ReadByte(); + if (status == 0) + { + pos = 0; + len = 0; + return false; + } + len = ReadInt32(); + pos = Pos; + return true; + } + + /// + /// 写入一个独立的数组包,值可以为null。 + /// + /// + /// + /// + public void WriteBytesPackage(byte[] value, int offset, int length) + { + if (value == null) + { + Write((byte)0); + } + else + { + Write((byte)1); + Write(length); + Write(value, offset, length); + } + } + + /// + /// 写入一个独立的数组包。值可以为null。 + /// + /// + public void WriteBytesPackage(byte[] value) + { + if (value == null) + { + WriteBytesPackage(value, 0, 0); + } + WriteBytesPackage(value, 0, value.Length); + } + + #endregion BytesPackage + + #region Int32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public int ReadInt32(bool? bigEndian = null) + { + int value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt32(Buffer, Pos); break; + } + m_position += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(int value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Int32 + + #region Int16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public short ReadInt16(bool? bigEndian = null) + { + short value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(short value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Int16 + + #region Int64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public long ReadInt64(bool? bigEndian = null) + { + long value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(long value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Int64 + + #region Boolean + + /// + /// 从当前流位置读取一个值 + /// + public bool ReadBoolean() + { + bool value = TouchSocketBitConverter.Default.ToBoolean(Buffer, Pos); + Pos += 1; + return value; + } + + /// + /// 写入值 + /// + /// + public void Write(bool value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value)); + } + + #endregion Boolean + + #region Byte + + /// + /// 写入值 + /// + /// + /// + public void Write(byte value) + { + Write(new byte[] { value }, 0, 1); + } + + #endregion Byte + + #region String + + /// + /// 从当前流位置读取一个值 + /// + public string ReadString() + { + int len = this.ReadInt32(); + if (len < 0) + { + return null; + } + else + { + string str = Encoding.UTF8.GetString(Buffer, Pos, len); + Pos += len; + return str; + } + } + + /// + /// 写入值。值可以为null,或者空。 + /// 注意:该操作不具备通用性,读取时必须使用ReadString。或者得先做出判断,由默认端序的int32值标识,具体如下: + /// + /// 小于0,表示字符串为null + /// 等于0,表示字符串为"" + /// 大于0,表示字符串在utf-8编码下的字节长度。 + /// + /// + /// + public void Write(string value) + { + if (value == null) + { + Write(-1); + } + else + { + byte[] buffer = Encoding.UTF8.GetBytes(value); + Write(buffer.Length); + Write(buffer); + } + } + + /// + /// 写入值。值必须为有效值。可通用解析。 + /// + /// + /// + public void WriteString(string value, Encoding encoding = null) + { + Write((encoding ?? Encoding.UTF8).GetBytes(value)); + } + + #endregion String + + #region Char + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public char ReadChar(bool? bigEndian = null) + { + char value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToChar(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToChar(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToChar(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(char value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Char + + #region Double + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public double ReadDouble(bool? bigEndian = null) + { + double value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToDouble(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToDouble(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToDouble(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(double value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Double + + #region Float + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public float ReadFloat(bool? bigEndian = null) + { + float value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToSingle(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToSingle(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToSingle(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(float value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion Float + + #region UInt16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ushort ReadUInt16(bool? bigEndian = null) + { + ushort value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(ushort value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion UInt16 + + #region UInt32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public uint ReadUInt32(bool? bigEndian = null) + { + uint value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt32(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(uint value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion UInt32 + + #region UInt64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ulong ReadUInt64(bool? bigEndian = null) + { + ulong value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public void Write(ulong value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + } + + #endregion UInt64 + + #region Null + + /// + /// 从当前流位置读取一个标识值,判断是否为null。 + /// + public bool ReadIsNull() + { + var status = ReadByte(); + if (status == 0) + { + return true; + } + else if (status == 1) + { + return false; + } + else + { + throw new Exception("标识既非Null,也非NotNull,可能是流位置发生了错误。"); + } + } + + /// + /// 判断该值是否为Null,然后写入标识值 + /// + public void WriteIsNull(T t) where T : class + { + if (t == null) + { + WriteNull(); + } + else + { + WriteNotNull(); + } + } + + /// + /// 写入一个标识非Null值 + /// + public void WriteNotNull() + { + Write((byte)1); + } + + /// + /// 写入一个标识Null值 + /// + public void WriteNull() + { + Write((byte)0); + } + + #endregion Null + + #region DateTime + + /// + /// 从当前流位置读取一个值 + /// + public DateTime ReadDateTime() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return DateTime.FromBinary(value); + } + + /// + /// 写入值 + /// + /// + public void Write(DateTime value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.ToBinary())); + } + + #endregion DateTime + + #region TimeSpan + + /// + /// 从当前流位置读取一个值 + /// + public TimeSpan ReadTimeSpan() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return TimeSpan.FromTicks(value); + } + + /// + /// 写入值 + /// + /// + public void Write(TimeSpan value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.Ticks)); + } + + #endregion TimeSpan + + #region Object + + /// + /// 从当前流位置读取一个泛型值 + /// + /// + /// + /// + public T ReadObject(SerializationType serializationType = SerializationType.FastBinary) + { + int length = ReadInt32(); + + if (length == 0) + { + return default; + } + + T obj; + + switch (serializationType) + { + case SerializationType.FastBinary: + { + obj = SerializeConvert.FastBinaryDeserialize(Buffer, Pos); + } + break; + + case SerializationType.Json: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.JsonDeserializeFromString(jsonString); + } + break; + + case SerializationType.Xml: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.XmlDeserializeFromString(jsonString); + } + break; + + case SerializationType.SystemBinary: + { + obj = SerializeConvert.BinaryDeserialize(Buffer, Pos, length); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Pos += length; + return obj; + } + + /// + /// 写入值 + /// + /// + /// + public void WriteObject(object value, SerializationType serializationType = SerializationType.FastBinary) + { + if (value == null) + { + Write(0); + } + byte[] data; + switch (serializationType) + { + case SerializationType.FastBinary: + { + data = SerializeConvert.FastBinarySerialize(value); + } + break; + + case SerializationType.Json: + { + data = SerializeConvert.JsonSerializeToBytes(value); + } + break; + + case SerializationType.Xml: + { + data = Encoding.UTF8.GetBytes(SerializeConvert.XmlSerializeToString(value)); + } + break; + + case SerializationType.SystemBinary: + { + data = SerializeConvert.BinarySerialize(value); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Write(data.Length); + Write(data); + } + + #endregion Object + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs.meta new file mode 100644 index 0000000..e55442c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69963a4ed1efd8b4292882fc18c40d1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching.meta new file mode 100644 index 0000000..b3da963 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 099facefef446734ca86eadc8cff4368 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs new file mode 100644 index 0000000..dcb52be --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 缓存实体 + /// + public class CacheEntry : ICacheEntry + { + /// + /// 缓存实体 + /// + /// + public CacheEntry(TKey key) : this(key, default) + { + } + + /// + /// 缓存实体 + /// + public CacheEntry(TKey key, TValue value) + { + UpdateTime = DateTime.Now; + Duration = TimeSpan.FromSeconds(60); + Key = key; + Value = value; + } + + /// + /// 有效区间。如果想长期有效,请使用 + /// + public TimeSpan Duration { get; set; } + + /// + /// 键 + /// + public TKey Key { get; set; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } + + /// + /// 值 + /// + public TValue Value { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs.meta new file mode 100644 index 0000000..c81b2c7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f36c7b895e102b4a81b60fee294aee8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs new file mode 100644 index 0000000..123f86b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// CacheExtensions + /// + public static class CacheManagementExtensions + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void AddCache(this ICache cacheManagement, TKey key, TValue value, int duration = 60 * 1000) + { + cacheManagement.AddCache(new CacheEntry(key) + { + Value = value, + Duration = TimeSpan.FromMilliseconds(duration) + }); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void SetCache(this ICache cacheManagement, TKey key, TValue value, int duration = 60 * 1000) + { + cacheManagement.SetCache(new CacheEntry(key) + { + Value = value, + Duration = TimeSpan.FromMilliseconds(duration) + }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs.meta new file mode 100644 index 0000000..dea7129 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1c861758d68ec041b7cb600b09a1c12 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs new file mode 100644 index 0000000..379e23f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 缓存键值 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial interface ICache + { + /// + /// 添加缓存。当缓存存在时,不会添加成功。 + /// + /// 缓存实体 + /// + bool AddCache(ICacheEntry entity); + + /// + /// 清空所有缓存 + /// + void ClearCache(); + + /// + /// 清空所有缓存 + /// + /// + Task ClearCacheAsync(); + + /// + /// 判断缓存是否存在,且在生命周期内。 + /// + /// + /// + /// + bool ContainsCache(TKey key); + + /// + /// 判断缓存是否存在,且在生命周期内。 + /// + /// + /// + /// + Task ContainsCacheAsync(TKey key); + + /// + /// 设置缓存,不管缓存存不存在,都会添加。 + /// + /// + /// + /// + bool SetCache(ICacheEntry entity); + + /// + /// 设置缓存,不管缓存存不存在,都会添加。 + /// + /// + /// + /// + Task SetCacheAsync(ICacheEntry entity); + + /// + /// 获取指定键的缓存。 + /// + /// 键 + /// + /// + ICacheEntry GetCache(TKey key); + + /// + /// 获取指定键的缓存。 + /// + /// 键 + /// + /// + Task> GetCacheAsync(TKey key); + + /// + /// 移除指定键的缓存。 + /// + /// 键 + /// + /// + bool RemoveCache(TKey key); + + /// + /// 移除指定键的缓存。 + /// + /// 键 + /// + /// + Task RemoveCacheAsync(TKey key); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs.meta new file mode 100644 index 0000000..734b00a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 036e455d275f6c642967a23b65a1372e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs new file mode 100644 index 0000000..f591697 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 缓存实体接口 + /// + public interface ICacheEntry + { + /// + /// 有效区间。如果想长期有效,请使用 + /// + public TimeSpan Duration { get; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } + } + + /// + /// 缓存实体接口 + /// + public interface ICacheEntry : ICacheEntry + { + /// + /// 键 + /// + public TKey Key { get; } + + /// + /// 值 + /// + public TValue Value { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs.meta new file mode 100644 index 0000000..4d42300 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 186923a2693c896438dff3ee3e9a97c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs new file mode 100644 index 0000000..8399612 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs @@ -0,0 +1,319 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 一个简单的内存缓存 + /// + public class MemoryCache : IEnumerable>, ICache + { + private readonly ConcurrentDictionary> m_pairs = new ConcurrentDictionary>(); + private readonly Timer m_timer; + + /// + /// 一个简单的内存缓存 + /// + public MemoryCache() + { + m_timer = new Timer((o) => + { + List list = new List(); + foreach (var item in m_pairs) + { + if (DateTime.Now - item.Value.UpdateTime > item.Value.Duration) + { + list.Add(item.Key); + } + } + foreach (var item in list) + { + OnRemove(item, out _); + } + }, null, 0, 60 * 1000); + } + + /// + /// 当每个元素超时被移除时触发。 + /// + public Action> Remove { get; set; } + + /// + /// + /// + /// + public bool AddCache(ICacheEntry entity) + { + return m_pairs.TryAdd(entity.Key, entity); + } + + /// + /// + /// + /// + /// + public Task AddCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return AddCache(entity); + }); + } + + /// + /// 清空所有缓存 + /// + public void ClearCache() + { + m_pairs.Clear(); + } + + /// + /// + /// + /// + public Task ClearCacheAsync() + { + return EasyTask.Run(() => + { + ClearCache(); + }); + } + + /// + /// + /// + /// + /// + public bool ContainsCache(TKey key) + { + if (m_pairs.TryGetValue(key, out ICacheEntry cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + return true; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + OnRemove(key, out _); + return false; + } + else + { + return true; + } + } + } + return false; + } + + /// + /// + /// + /// + /// + public Task ContainsCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return ContainsCache(key); + }); + } + + /// + /// 获取缓存实体。 + /// + /// + /// + public ICacheEntry GetCache(TKey key) + { + ICacheEntry cache; + if (m_pairs.TryGetValue(key, out cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + return cache; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + OnRemove(key, out _); + return default; + } + else + { + return cache; + } + } + } + return default; + } + + /// + /// + /// + /// + /// + public Task> GetCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return GetCache(key); + }); + } + + /// + /// + /// + /// + public IEnumerator> GetEnumerator() + { + return m_pairs.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 移除缓存 + /// + /// + /// + /// + public bool RemoveCache(TKey key, out ICacheEntry entity) + { + return OnRemove(key, out entity); + } + + /// + /// 移除缓存 + /// + /// + /// + public bool RemoveCache(TKey key) + { + return OnRemove(key, out _); + } + + /// + /// + /// + /// + /// + public Task RemoveCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return RemoveCache(key); + }); + } + + /// + /// + /// + /// + /// + public bool SetCache(ICacheEntry entity) + { + m_pairs.AddOrUpdate(entity.Key, entity, (k, v) => + { + return entity; + }); + return true; + } + + /// + /// + /// + /// + /// + public Task SetCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return SetCache(entity); + }); + } + + /// + /// 获取对应的值。 + /// + /// + /// + /// + /// + public bool TryGetValue(TKey key, out TValue value, bool update = false) + { + if (m_pairs.TryGetValue(key, out ICacheEntry cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + if (update) + { + cache.UpdateTime = DateTime.Now; + } + value = cache.Value; + return true; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + RemoveCache(key); + value = default; + return false; + } + else + { + if (update) + { + cache.UpdateTime = DateTime.Now; + } + value = (TValue)cache.Value; + return true; + } + } + } + value = default; + return false; + } + + private bool OnRemove(TKey key, out ICacheEntry cache) + { + if (m_pairs.TryRemove(key, out cache)) + { + try + { + Remove?.Invoke(cache); + return true; + } + catch + { + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs.meta new file mode 100644 index 0000000..cbaf39c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 595e92394929b464db002876421876cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections.meta new file mode 100644 index 0000000..d0d1c42 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b55d252855eec1e41848165741d9255d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent.meta new file mode 100644 index 0000000..414fc8b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba1a0091c88ead841b9bd84996f3716e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs new file mode 100644 index 0000000..6ad3fb1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 安全双向字典 + /// + public class ConcurrentDoublyDictionary + { + private readonly ConcurrentDictionary m_keyToValue; + private readonly ConcurrentDictionary m_valueToKey; + + /// + /// 构造函数 + /// + public ConcurrentDoublyDictionary() + { + m_keyToValue = new ConcurrentDictionary(); + m_valueToKey = new ConcurrentDictionary(); + } + + /// + /// 由键指向值得集合 + /// + public ConcurrentDictionary KeyToValue => m_keyToValue; + + /// + /// 由值指向键的集合 + /// + public ConcurrentDictionary ValueToKey => m_valueToKey; + + /// + /// 尝试将指定的键和值添加到字典中。 + /// + /// + /// + /// + public bool TryAdd(TKey key, TValue value) + { + if (m_keyToValue.TryAdd(key, value)) + { + if (m_valueToKey.TryAdd(value, key)) + { + return true; + } + else + { + m_keyToValue.TryRemove(key, out _); + return false; + } + } + return false; + } + + /// + /// 由键尝试移除 + /// + /// + /// + /// + public bool TryRemoveFromKey(TKey key, out TValue value) + { + if (m_keyToValue.TryRemove(key, out value)) + { + if (m_valueToKey.TryRemove(value, out _)) + { + return true; + } + } + return false; + } + + /// + /// 由值尝试移除 + /// + /// + /// + /// + public bool TryRemoveFromValue(TValue value, out TKey key) + { + if (m_valueToKey.TryRemove(value, out key)) + { + if (m_keyToValue.TryRemove(key, out _)) + { + return true; + } + } + return false; + } + + /// + /// 由键获取到值 + /// + /// + /// + /// + public bool TryGetFromKey(TKey key, out TValue value) + { + return m_keyToValue.TryGetValue(key, out value); + } + + /// + /// 由值获取到键 + /// + /// + /// + /// + public bool TryGetFromValue(TValue value, out TKey key) + { + return m_valueToKey.TryGetValue(value, out key); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs.meta new file mode 100644 index 0000000..644b6a3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e247cd100a0596046a960c4d9dabbd81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs new file mode 100644 index 0000000..7ed58cf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs @@ -0,0 +1,680 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 线程安全的List,其基本操作和List一致。 + /// + /// + public class ConcurrentList : IList + { + private readonly List m_list; + + /// + /// 构造函数 + /// + /// + public ConcurrentList(IEnumerable collection) + { + m_list = new List(collection); + } + + /// + /// 构造函数 + /// + public ConcurrentList() + { + m_list = new List(); + } + + /// + /// 构造函数 + /// + /// + public ConcurrentList(int capacity) + { + m_list = new List(capacity); + } + + /// + /// 元素数量 + /// + public int Count + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Count; + } + } + } + + /// + /// 是否为只读 + /// + public bool IsReadOnly => false; + + /// + /// 获取索引元素 + /// + /// + /// + public T this[int index] + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list[index]; + } + } + set + { + lock (((ICollection)m_list).SyncRoot) + { + m_list[index] = value; + } + } + } + + /// + /// 添加元素 + /// + /// + public void Add(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Add(item); + } + } + + /// + /// 清空所有元素 + /// + public void Clear() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Clear(); + } + } + + /// + /// 是否包含某个元素 + /// + /// + /// + public bool Contains(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Contains(item); + } + } + + /// + /// 复制到 + /// + /// + /// + public void CopyTo(T[] array, int arrayIndex) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.CopyTo(array, arrayIndex); + } + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ToList().GetEnumerator(); + } + } + + /// + /// 返回迭代器组合 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + lock (((ICollection)m_list).SyncRoot) + { + return GetEnumerator(); + } + } + + /// + /// 索引 + /// + /// + /// + public int IndexOf(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item); + } + } + + /// + /// 插入 + /// + /// + /// + public void Insert(int index, T item) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Insert(index, item); + } + } + + /// + /// 移除元素 + /// + /// + /// + public bool Remove(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Remove(item); + } + } + + /// + /// 按索引移除 + /// + /// + public void RemoveAt(int index) + { + lock (((ICollection)m_list).SyncRoot) + { + if (index < m_list.Count) + { + m_list.RemoveAt(index); + } + } + } + + /// + /// 获取或设置容量 + /// + public int Capacity + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Capacity; + } + } + set + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Capacity = value; + } + } + } + + /// + /// + /// + /// + public void AddRange(IEnumerable collection) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.AddRange(collection); + } + } + + /// + /// + /// + /// + /// + public int BinarySearch(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(item); + } + } + + /// + /// + /// + /// + /// + /// + public int BinarySearch(T item, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(item, comparer); + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + public int BinarySearch(int index, int count, T item, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(index, count, item, comparer); + } + } + + /// + /// + /// + /// + /// + /// + public List ConvertAll(Converter converter) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ConvertAll(converter); + } + } + + /// + /// + /// + /// + /// + public T Find(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Find(match); + } + } + + /// + /// + /// + /// + /// + public List FindAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindAll(match); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int FindIndex(int startIndex, int count, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(startIndex, count, match); + } + } + + /// + /// + /// + /// + /// + /// + public int FindIndex(int startIndex, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(startIndex, match); + } + } + + /// + /// + /// + /// + /// + public int FindIndex(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(match); + } + } + + /// + /// + /// + /// + /// + public T FindLast(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLast(match); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int FindLastIndex(int startIndex, int count, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(startIndex, count, match); + } + } + + /// + /// + /// + /// + /// + /// + public int FindLastIndex(int startIndex, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(startIndex, match); + } + } + + /// + /// + /// + /// + /// + public int FindLastIndex(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(match); + } + } + + /// + /// + /// + /// + public void ForEach(Action action) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.ForEach(action); + } + } + + /// + /// + /// + /// + /// + /// + public List GetRange(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.GetRange(index, count); + } + } + + /// + /// + /// + /// + /// + /// + public int IndexOf(T item, int index) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item, index); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int IndexOf(T item, int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item, index, count); + } + } + + /// + /// + /// + /// + /// + public void InsertRange(int index, IEnumerable collection) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.InsertRange(index, collection); + } + } + + /// + /// + /// + /// + /// + public int LastIndexOf(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item); + } + } + + /// + /// + /// + /// + /// + /// + public int LastIndexOf(T item, int index) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.LastIndexOf(item, index); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int LastIndexOf(T item, int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.LastIndexOf(item, index, count); + } + } + + /// + /// + /// + /// + public void RemoveAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.RemoveAll(match); + } + } + + /// + /// + /// + /// + /// + public void RemoveRange(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.RemoveRange(index, count); + } + } + + /// + /// + /// + public void Reverse() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Reverse(); + } + } + + /// + /// + /// + /// + /// + public void Reverse(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Reverse(index, count); + } + } + + /// + /// + /// + public void Sort() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(); + } + } + + /// + /// + /// + /// + public void Sort(Comparison comparison) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(comparison); + } + } + + /// + /// + /// + /// + public void Sort(IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(comparer); + } + } + + /// + /// + /// + /// + /// + /// + public void Sort(int index, int count, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(index, count, comparer); + } + } + + /// + /// + /// + /// + public T[] ToArray() + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ToArray(); + } + } + + /// + /// + /// + public void TrimExcess() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.TrimExcess(); + } + } + + /// + /// + /// + /// + /// + public bool TrueForAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.TrueForAll(match); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs.meta new file mode 100644 index 0000000..7a4393b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a03d08c18b538c478ee7a58941caf96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs new file mode 100644 index 0000000..9bf73c9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs @@ -0,0 +1,194 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 三元组合 + /// + /// + /// + /// + public readonly struct Ternary + { + /// + /// 三元组合 + /// + /// + /// + /// + public Ternary(TKey1 key1, TKey2 key2, TValue value) + { + Key1 = key1; + Key2 = key2; + Value = value; + } + + /// + /// 首键 + /// + public readonly TKey1 Key1 { get; } + + /// + /// 次键 + /// + public readonly TKey2 Key2 { get; } + + /// + /// 值 + /// + public readonly TValue Value { get; } + } + + /// + /// 线程安全的双键字典 + /// + /// + /// + /// + public class ConcurrentMultiDictionary + { + private readonly ConcurrentDictionary> m_key1ToValue = + new ConcurrentDictionary>(); + + private readonly ConcurrentDictionary> m_key2ToValue = + new ConcurrentDictionary>(); + + /// + /// 元素数量。 + /// + public int Count { get => m_key1ToValue.Count; } + + /// + /// 清空所有元素。 + /// + public void Clear() + { + m_key1ToValue.Clear(); + m_key2ToValue.Clear(); + } + + /// + /// 是否包含指定键。 + /// + /// + /// + public bool ContainsKey(TKey2 key) + { + return m_key2ToValue.ContainsKey(key); + } + + /// + /// 是否包含指定键。 + /// + /// + /// + public bool ContainsKey(TKey1 key) + { + return m_key1ToValue.ContainsKey(key); + } + + /// + /// 尝试添加。 + /// + /// + /// + /// + /// + public bool TryAdd(TKey1 key1, TKey2 key2, TValue value) + { + var ternary = new Ternary(key1, key2, value); + if (m_key1ToValue.TryAdd(key1, ternary) && m_key2ToValue.TryAdd(key2, ternary)) + { + return true; + } + else + { + m_key1ToValue.TryRemove(key1, out _); + m_key2ToValue.TryRemove(key2, out _); + return false; + } + } + + /// + /// 由首键删除 + /// + /// + /// + /// + public bool TryRemove(TKey1 key, out TValue value) + { + if (m_key1ToValue.TryRemove(key, out var ternary)) + { + m_key2ToValue.TryRemove(ternary.Key2, out _); + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由次键删除 + /// + /// + /// + /// + public bool TryRemove(TKey2 key, out TValue value) + { + if (m_key2ToValue.TryRemove(key, out var ternary)) + { + m_key1ToValue.TryRemove(ternary.Key1, out _); + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由首键获取值 + /// + /// + /// + /// + public bool TryGetValue(TKey1 key, out TValue value) + { + if (m_key1ToValue.TryGetValue(key, out var ternary)) + { + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由次键获取值 + /// + /// + /// + /// + public bool TryGetValue(TKey2 key, out TValue value) + { + if (m_key2ToValue.TryGetValue(key, out var ternary)) + { + value = ternary.Value; + return true; + } + value = default; + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs.meta new file mode 100644 index 0000000..4bd5de0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d48f1d5ad25c0f24cbb44c2688506d63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs new file mode 100644 index 0000000..e86a8bd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 智能安全队列 + /// + /// + public class IntelligentConcurrentQueue : ConcurrentQueue + { + private int m_count; + + private readonly int m_maxCount; + + /// + /// 构造函数 + /// + /// + public IntelligentConcurrentQueue(int maxCount) + { + m_maxCount = maxCount; + } + + /// + /// 允许的最大长度 + /// + public int MaxCount => m_maxCount; + + /// + /// 长度 + /// + public new int Count => m_count; + + /// + /// 入队 + /// + /// + public new void Enqueue(T item) + { + SpinWait.SpinUntil(Check); + Interlocked.Increment(ref m_count); + base.Enqueue(item); + } + + /// + /// 出队 + /// + /// + /// + public new bool TryDequeue(out T result) + { + if (base.TryDequeue(out result)) + { + Interlocked.Decrement(ref m_count); + return true; + } + return false; + } + + private bool Check() + { + return m_count < m_maxCount; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs.meta new file mode 100644 index 0000000..4a4152e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29754dfd266b0d44fa5cbdea9915b2f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs new file mode 100644 index 0000000..fdf1a1b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs @@ -0,0 +1,233 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 队列数据 + /// + public interface IQueueData + { + /// + /// 数据长度 + /// + int Size { get; } + } + + /// + /// 传输字节 + /// + public class QueueDataBytes : IQueueData + { + /// + /// 构造函数 + /// + /// + /// + /// + public QueueDataBytes(byte[] buffer, int offset, int length) + { + Offset = offset; + Length = length; + Buffer = buffer; + Size = length; + } + + /// + /// 从指定内存创建一个新对象,且内存也为新创建。 + /// + /// + /// + /// + /// + public static QueueDataBytes CreateNew(byte[] buffer, int offset, int length) + { + byte[] buf = new byte[length]; + Array.Copy(buffer, offset, buf, 0, length); + return new QueueDataBytes(buf); + } + + /// + /// 构造函数 + /// + /// + public QueueDataBytes(byte[] buffer) : this(buffer, 0, buffer.Length) + { + } + + /// + /// 数据内存 + /// + public byte[] Buffer { get; } + + /// + /// 长度 + /// + public int Length { get; } + + /// + /// 偏移 + /// + public int Offset { get; } + + /// + /// 尺寸 + /// + public int Size { get; } + } + + /// + /// 智能数据安全队列 + /// + /// + public class IntelligentDataQueue : ConcurrentQueue where T : IQueueData + { + private long m_actualSize; + private bool m_free; + private long m_maxSize; + private Action m_onQueueChanged; + private bool m_overflowWait; + + /// + /// 构造函数 + /// + /// + public IntelligentDataQueue(long maxSize) + { + m_free = true; + m_overflowWait = true; + MaxSize = maxSize; + } + + /// + /// 构造函数 + /// + public IntelligentDataQueue() : this(1024 * 1024 * 10) + { + } + + /// + /// 实际尺寸 + /// + public long ActualSize => m_actualSize; + + /// + /// 是否有空位允许入队 + /// + public bool Free => m_free; + + /// + /// 允许的最大长度 + /// + public long MaxSize + { + get => m_maxSize; + set + { + if (value < 1) + { + value = 1; + } + m_maxSize = value; + } + } + + /// + /// 在队列修改时 + /// + public Action OnQueueChanged + { + get => m_onQueueChanged; + set => m_onQueueChanged = value; + } + + /// + /// 溢出等待 + /// + public bool OverflowWait + { + get => m_overflowWait; + set => m_overflowWait = value; + } + + /// + /// 超时时间。默认1000*30ms; + /// + public int Timeout { get; set; } = 1000 * 30; + + /// + /// 清空队列 + /// + public void Clear(Action onClear) + { + while (base.TryDequeue(out T t)) + { + onClear?.Invoke(t); + } + } + + /// + /// 入队 + /// + /// + public new void Enqueue(T item) + { + lock (this) + { + bool free = m_actualSize < m_maxSize; + if (m_free != free) + { + m_free = free; + m_onQueueChanged?.Invoke(m_free); + } + + if (m_overflowWait) + { + SpinWait.SpinUntil(Check, Timeout); + } + + Interlocked.Add(ref m_actualSize, item.Size); + base.Enqueue(item); + } + } + + /// + /// 出队 + /// + /// + /// + public new bool TryDequeue(out T result) + { + if (base.TryDequeue(out result)) + { + Interlocked.Add(ref m_actualSize, -result.Size); + bool free = m_actualSize < m_maxSize; + if (m_free != free) + { + m_free = free; + m_onQueueChanged?.Invoke(m_free); + } + return true; + } + return false; + } + + private bool Check() + { + return m_actualSize < m_maxSize; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs.meta new file mode 100644 index 0000000..b25c0fb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb105b942646d4d40a0a70436afdb4d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs new file mode 100644 index 0000000..8bc3ee2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs @@ -0,0 +1,150 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 触发器队列 + /// + /// + public class TriggerQueue : DisposableObject + { + private readonly ReaderWriterLockSlim m_lockSlim; + private readonly ConcurrentQueue m_queue; + private readonly Timer m_timer; + private volatile bool m_sending; + + /// + /// 触发器队列 + /// + public TriggerQueue() + { + m_lockSlim = new ReaderWriterLockSlim(); + m_queue = new ConcurrentQueue(); + m_timer = new Timer(TimerRun, null, 10, 10); + } + + /// + /// 析构函数 + /// + ~TriggerQueue() + { + Dispose(false); + } + + /// + /// 出队列处理。 + /// + public Action OnDequeue { get; set; } + + /// + /// 发生错误 + /// + public Action OnError { get; set; } + + /// + /// 是否处于发送状态 + /// + public bool Sending + { + get + { + using (new ReadLock(m_lockSlim)) + { + return m_sending; + } + } + + private set + { + using (new WriteLock(m_lockSlim)) + { + m_sending = value; + } + } + } + + /// + /// 发送 + /// + public void Enqueue(T data) + { + m_queue.Enqueue(data); + if (SwitchToRun()) + { + ThreadPool.QueueUserWorkItem(BeginTrigger); + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_queue.Clear(); + base.Dispose(disposing); + } + + private void BeginTrigger(object o) + { + while (true) + { + try + { + if (m_queue.TryDequeue(out T data)) + { + OnDequeue?.Invoke(data); + } + else + { + break; + } + } + catch (Exception ex) + { + OnError?.Invoke(ex); + } + } + Sending = false; + } + + private bool SwitchToRun() + { + using (new ReadLock(m_lockSlim)) + { + if (m_sending) + { + return false; + } + else + { + m_sending = true; + return true; + } + } + } + + private void TimerRun(object state) + { + if (SwitchToRun()) + { + BeginTrigger(null); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs.meta new file mode 100644 index 0000000..747ab32 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6c2b97fb85402b4aacc29a71b0d1784 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs new file mode 100644 index 0000000..371bd09 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// IgnoreCaseNameValueCollection + /// + [DebuggerTypeProxy(typeof(NameValueCollectionDebugView))] + public class IgnoreCaseNameValueCollection : NameValueCollection + { + /// + /// IgnoreCaseNameValueCollection + /// + public IgnoreCaseNameValueCollection() : base(StringComparer.OrdinalIgnoreCase) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs.meta new file mode 100644 index 0000000..5ea5615 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11250ac29f2560a478feec47aac8d9dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs new file mode 100644 index 0000000..ebfbeb6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// NameValueCollectionDebugView + /// + public class NameValueCollectionDebugView + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly NameValueCollection m_nameValue; + + /// + /// NameValueCollectionDebugView + /// + /// + public NameValueCollectionDebugView(NameValueCollection nameValue) + { + m_nameValue = nameValue; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + private Dictionary KV + { + get + { + var dic = new Dictionary(); + foreach (var item in m_nameValue.AllKeys) + { + dic.TryAdd(item, m_nameValue[item]); + } + return dic; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs.meta new file mode 100644 index 0000000..b52545f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be3c35ae29a02064ea1bb53301d80a47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common.meta new file mode 100644 index 0000000..a0cf0ec --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98b94db8e772cf14f8654cb30632412e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs new file mode 100644 index 0000000..ac83754 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// 运行配置类 + /// + public abstract class AppConfigBase + { + private readonly string m_fullPath; + + /// + /// 构造函数 + /// + /// + public AppConfigBase(string fullPath) + { + if (string.IsNullOrEmpty(fullPath)) + { + throw new ArgumentException($"“{nameof(fullPath)}”不能为 null 或空。", nameof(fullPath)); + } + + m_fullPath = fullPath; + } + + /// + /// 保存配置 + /// + /// + /// + /// + public bool Save(bool overwrite, out string msg) + { + if (overwrite == false && File.Exists(m_fullPath)) + { + msg = null; + return true; + } + try + { + File.WriteAllText(m_fullPath, this.ToJson()); + msg = null; + return true; + } + catch (Exception ex) + { + msg = ex.Message; + return false; + } + } + + /// + /// 加载配置 + /// + /// + /// + public bool Load(out string msg) + { + try + { + if (!File.Exists(m_fullPath)) + { + Save(false, out _); + } + var obj = File.ReadAllText(m_fullPath).FromJson(GetType()); + var ps = GetType().GetProperties(); + + foreach (var item in ps) + { + item.SetValue(this, item.GetValue(obj)); + } + msg = null; + return true; + } + catch (Exception ex) + { + msg = ex.Message; + return false; + } + } + + /// + /// 获取默认配置。 + /// + /// + /// + public static T GetDefault() where T : AppConfigBase, new() + { + Type type = typeof(T); + if (list.TryGetValue(type, out object value)) + { + return (T)value; + } + T _default = ((T)Activator.CreateInstance(typeof(T))); + _default.Load(out _); + list.Add(type, _default); + return _default; + } + + private static readonly Dictionary list = new Dictionary(); + + /// + /// 获取默认配置,每次调用该方法时,都会重新加载配置。 + /// + /// + /// + public static T GetNewDefault() where T : AppConfigBase, new() + { + T _default = ((T)Activator.CreateInstance(typeof(T))); + _default.Load(out _); + if (list.ContainsKey(_default.GetType())) + { + list[_default.GetType()] = _default; + } + else + { + list.Add(_default.GetType(), _default); + } + return _default; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs.meta new file mode 100644 index 0000000..5ef5d7e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9867e63be774a84a9f14ff6e552458c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs new file mode 100644 index 0000000..139bd56 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// DateExtensions + /// + public static class DateExtensions + { + private static readonly DateTime m_utc_time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// 将时间转为毫秒级别的短整形 + /// + /// + /// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertTime(this in DateTime time) + { + return (uint)(Convert.ToInt64(time.Subtract(m_utc_time).TotalMilliseconds) & 0xffffffff); + } + + private static readonly DateTimeOffset m_utc1970 = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + /// + /// 将时间转为毫秒级别的短整形 + /// + /// + /// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertTime(this in DateTimeOffset time) + { + return (uint)(Convert.ToInt64(time.Subtract(m_utc1970).TotalMilliseconds) & 0xffffffff); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs.meta new file mode 100644 index 0000000..b195221 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1849d956dfbc9c543a8ce47583057ece +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs new file mode 100644 index 0000000..78723a3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 具有释放的对象。 + /// 并未实现析构函数相关。 + /// + public class DisposableObject : IDisposable + { + /// + /// 判断是否已释放。 + /// + private volatile bool m_disposedValue; + + /// + /// 标识该对象是否已被释放 + /// + public bool DisposedValue { get => m_disposedValue; } + + /// + /// 调用释放,切换释放状态。 + /// + /// + protected virtual void Dispose(bool disposing) + { + m_disposedValue = true; + } + + /// + /// 释放资源 + /// + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs.meta new file mode 100644 index 0000000..4ee5527 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 098bd4ca8caafe4438d1d84848efb2e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum.meta new file mode 100644 index 0000000..6798f94 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 14e59c4a77808be46beceda3f004a031 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs new file mode 100644 index 0000000..51608bc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 大小端类型 + /// + public enum EndianType + { + /// + /// 小端模式 + /// + Little, + + /// + /// 大端模式 + /// + Big + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs.meta new file mode 100644 index 0000000..b72a0db --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b45121987fff984cba719258e7e1456 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs new file mode 100644 index 0000000..c3ebc13 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 结果类型 + /// + public enum ResultCode + { + /// + /// 默认 + /// + Default, + + /// + /// 错误 + /// + Error, + + /// + /// 异常 + /// + Exception, + + /// + /// 成功 + /// + Success, + + /// + /// 失败 + /// + Fail, + + /// + /// 操作超时 + /// + Overtime, + + /// + /// 操作取消 + /// + Canceled + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs.meta new file mode 100644 index 0000000..953439d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 19e1a3a617d052143868cbedcb3e4187 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs new file mode 100644 index 0000000..04fed76 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 流量控制 + /// + public class FlowGate + { + private readonly Stopwatch m_stopwatch; + + private long m_timeTick; + + private long m_transferLength; + + /// + /// 构造函数 + /// + public FlowGate() + { + m_stopwatch = new Stopwatch(); + } + + /// + /// 最大值 + /// + public long Maximum { get; set; } = long.MaxValue; + + /// + /// 最长休眠周期。默认为5*1000ms. + /// 当设置为5000时,假如设置的=10,而一次递增了100,则理应会休眠10s,但是会休眠5s。反之,如果设置1,则每秒周期都会清空。 + /// + public int MaximumPeriod { get; set; } = 5000; + + /// + /// 检测等待 + /// + public void AddCheckWait(int increment) + { + if (GetNowTick() - m_timeTick > 0) + { + //时间过了一秒 + m_timeTick = FlowGate.GetNowTick(); + m_transferLength = 0; + m_stopwatch.Restart(); + } + else + { + //在这一秒中 + if (Interlocked.Add(ref m_transferLength, increment) > Maximum) + { + //上传饱和 + m_stopwatch.Stop(); + int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds; + Thread.Sleep(sleepTime); + } + } + } + + /// + /// 检测等待 + /// + /// + /// + public async Task AddCheckWaitAsync(int increment) + { + if (GetNowTick() - m_timeTick > 0) + { + //时间过了一秒 + m_timeTick = FlowGate.GetNowTick(); + m_transferLength = 0; + m_stopwatch.Restart(); + } + else + { + //在这一秒中 + if (Interlocked.Add(ref m_transferLength, increment) > Maximum) + { + //上传饱和 + m_stopwatch.Stop(); + int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds; + await Task.Delay(sleepTime); + } + } + } + + private static long GetNowTick() + { + return DateTime.Now.Ticks / 10000000; + } + + private int GetBaseNum() + { + return Math.Min((int)((double)m_transferLength / Maximum * 1000), MaximumPeriod); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs.meta new file mode 100644 index 0000000..e935ba6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4689ab5bc6521f46a2d68803ca37c5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs new file mode 100644 index 0000000..e62cf11 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 全局环境设置 + /// + public static class GlobalEnvironment + { + /// + /// 优化平台 + /// + public static OptimizedPlatforms OptimizedPlatforms { get; set; } = OptimizedPlatforms.None; + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs.meta new file mode 100644 index 0000000..ded406d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80ef6598836450a4f9113b6a296273d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs new file mode 100644 index 0000000..b91f03a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 返回通知接口 + /// + public interface IResult + { + /// + /// 是否成功 + /// + ResultCode ResultCode { get; } + + /// + /// 消息 + /// + string Message { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs.meta new file mode 100644 index 0000000..1b8d1fa --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48b972e26ce8863458619f3663b6d53e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs new file mode 100644 index 0000000..d9e3387 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 规范写端口,提供更多扩展 + /// + public interface IWrite + { + /// + /// 写入 + /// + /// + /// + /// + void Write(byte[] buffer, int offset, int length); + + /// + /// 写入 + /// + /// + void Write(byte[] buffer); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs.meta new file mode 100644 index 0000000..991104c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bae72788654fb64f806e8bac94906dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs new file mode 100644 index 0000000..a7d4545 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 读取锁 + /// + public struct ReadLock : IDisposable + { + private readonly ReaderWriterLockSlim m_locks; + + /// + /// 构造函数 + /// + /// + public ReadLock(ReaderWriterLockSlim locks) + { + m_locks = locks; + m_locks.EnterReadLock(); + } + + /// + /// 释放 + /// + public void Dispose() + { + m_locks.ExitReadLock(); + } + } + + /// + /// 写入锁 + /// + public struct WriteLock : IDisposable + { + private readonly ReaderWriterLockSlim m_locks; + + /// + /// 构造函数 + /// + /// + public WriteLock(ReaderWriterLockSlim locks) + { + m_locks = locks; + m_locks.EnterWriteLock(); + } + + /// + /// 释放 + /// + public void Dispose() + { + m_locks.ExitWriteLock(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs.meta new file mode 100644 index 0000000..d49d6ea --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bbeafbb054eb83459ecdf79e7201b4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs new file mode 100644 index 0000000..83f2219 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Specialized; + +namespace TouchSocket.Core +{ + /// + /// 元数据键值对。 + /// + [FastConverter(typeof(MetadataFastBinaryConverter))] + public class Metadata : NameValueCollection, IPackage + { + /// + /// 元数据键值对。 + /// + public Metadata() + { + } + + /// + /// 添加。如果键存在,将被覆盖。 + /// + /// + /// + public new Metadata Add(string name, string value) + { + base.Add(name, value); + return this; + } + + /// + /// 打包 + /// + /// + public void Package(ByteBlock byteBlock) + { + byteBlock.Write(Count); + foreach (var item in AllKeys) + { + byteBlock.Write(item); + byteBlock.Write(this[item]); + } + } + + /// + /// 解包 + /// + /// + public void Unpackage(ByteBlock byteBlock) + { + int count = byteBlock.ReadInt32(); + for (int i = 0; i < count; i++) + { + string key = byteBlock.ReadString(); + string value = byteBlock.ReadString(); + Add(key, value); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs.meta new file mode 100644 index 0000000..af70b68 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0789c6c3fa93cbb4da810452431d0acc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs new file mode 100644 index 0000000..622bc1c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// MetadataFastBinaryConverter + /// + internal sealed class MetadataFastBinaryConverter : FastBinaryConverter + { + protected override Metadata Read(byte[] buffer, int offset, int len) + { + ByteBlock byteBlock = new ByteBlock(buffer); + byteBlock.Pos = offset; + Metadata metadata = new Metadata(); + while (byteBlock.Pos < offset + len) + { + metadata.Add(byteBlock.ReadString(), byteBlock.ReadString()); + } + return metadata; + } + + protected override int Write(ByteBlock byteBlock, Metadata obj) + { + int pos = byteBlock.Pos; + foreach (var item in obj.AllKeys) + { + byteBlock.Write(item); + byteBlock.Write(obj[item]); + } + return byteBlock.Pos - pos; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs.meta new file mode 100644 index 0000000..669e451 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb1c84fb8e237ae4eba0e332013c3d85 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs new file mode 100644 index 0000000..ae43ab0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 优化平台 + /// + [Flags] + public enum OptimizedPlatforms + { + /// + /// 无特殊优化 + /// + None=0, + + /// + /// 针对Unity2020及以下优化。 + /// 一般来说,当在unity2020及以下版本,中执行il2cpp编译时,需要设置该值。 + /// + Unity = 1 + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs.meta new file mode 100644 index 0000000..6a19ac7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: acd6e3804c9a0494cb6e825c390087c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs new file mode 100644 index 0000000..d805d99 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs @@ -0,0 +1,268 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 结果返回 + /// + public struct Result : IResult + { + /// + /// 成功 + /// + public static readonly Result Success = new Result(ResultCode.Success, "Success"); + + /// + /// 初始状态 + /// + public static readonly Result Default = new Result(ResultCode.Default, "Default"); + + /// + /// 未知失败 + /// + public static readonly Result UnknownFail = new Result(ResultCode.Fail, TouchSocketStatus.UnknownError.GetDescription()); + + /// + /// 超时 + /// + public static readonly Result Overtime = new Result(ResultCode.Overtime, TouchSocketStatus.Overtime.GetDescription()); + + /// + /// 取消 + /// + public static readonly Result Canceled = new Result(ResultCode.Canceled, TouchSocketStatus.Canceled.GetDescription()); + + /// + /// 构造函数 + /// + /// + /// + public Result(ResultCode resultCode, string message) + { + ResultCode = resultCode; + Message = message; + } + + /// + /// 构造函数 + /// + /// + public Result(IResult result) + { + ResultCode = result.ResultCode; + Message = result.Message; + } + + /// + /// 构造函数 + /// + /// + public Result(Exception exception) + { + ResultCode = ResultCode.Exception; + Message = exception.Message; + } + + /// + /// 构造函数 + /// + /// + public Result(ResultCode resultCode) + { + ResultCode = resultCode; + Message = resultCode.GetDescription(); + } + + /// + /// + /// + public ResultCode ResultCode { get; private set; } + + /// + /// + /// + public string Message { get; private set; } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromCanceled(string msg) + { + return new Result(ResultCode.Canceled, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromError(string msg) + { + return new Result(ResultCode.Error, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromException(string msg) + { + return new Result(ResultCode.Exception, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromFail(string msg) + { + return new Result(ResultCode.Fail, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromOvertime(string msg) + { + return new Result(ResultCode.Overtime, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromSuccess(string msg) + { + return new Result(ResultCode.Success, msg); + } + + /// + /// ToString + /// + /// + public override string ToString() + { + return $"类型:{ResultCode},信息:{Message}"; + } + } + + /// + /// 结果返回 + /// + public class ResultBase : IResult + { + /// + /// 构造函数 + /// + /// + /// + public ResultBase(ResultCode resultCode, string message) + { + ResultCode = resultCode; + Message = message; + } + + /// + /// 构造函数 + /// + /// + public ResultBase(ResultCode resultCode) + { + ResultCode = resultCode; + Message = resultCode.GetDescription(); + } + + /// + /// 构造函数 + /// + /// + public ResultBase(Result result) + { + ResultCode = result.ResultCode; + Message = result.Message; + } + + /// + /// 构造函数 + /// + public ResultBase() + { + } + + /// + /// + /// + public ResultCode ResultCode { get; protected set; } + + /// + /// + /// + public string Message { get; protected set; } + + /// + /// ToString + /// + /// + public override string ToString() + { + return $"类型:{ResultCode},信息:{Message}"; + } + } + + /// + /// ResultExtensions + /// + public static class ResultExtensions + { + /// + /// 是否成功。 + /// + /// + /// + public static bool IsSuccess(this IResult result) + { + return result.ResultCode == ResultCode.Success; + } + + /// + /// 是否没有成功。 + /// + /// + /// + public static bool NotSuccess(this IResult result) + { + return result.ResultCode != ResultCode.Success; + } + + /// + /// 转换为 + /// + /// + /// + public static Result ToResult(this IResult result) + { + return new Result(result); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs.meta new file mode 100644 index 0000000..2834b5c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63d460dc347671f4a87ad1340148ef21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs new file mode 100644 index 0000000..970028d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 雪花ID生成器(该代码来自网络) + /// + public class SnowflakeIDGenerator + { + private const int SequenceBits = 10; + + /// + /// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + /// + private const long SequenceMask = -1L ^ -1L << SequenceBits; + + private const int TimestampLeftShift = SequenceBits + WorkerIdBits; + + private const int WorkerIdBits = 4; + + //计数器字节数,10个字节用来保存计数码 + private const int WorkerIdShift = SequenceBits; + + private static long Sequence = 0L; + + //机器ID + private static long WorkerId; + + private readonly long Twepoch = 687888001020L; + + private long m_lastTimestamp = -1L; + + static SnowflakeIDGenerator() + { + } + + //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + /// + /// 机器码 + /// + /// + public SnowflakeIDGenerator(long workerId) + { + if (workerId > MaxWorkerId || workerId < 0) + throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", MaxWorkerId)); + SnowflakeIDGenerator.WorkerId = workerId; + Twepoch = DateTime.Now.Ticks - 10000; + } + + /// + /// 最大机器ID + /// + public static long MaxWorkerId { get; private set; } = -1L ^ (-1L << WorkerIdBits); //最大机器ID + + //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳 + //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义) + + //机器码数据左移位数,就是后面计数器占用的位数 + //时间戳左移动位数就是机器码和计数器总字节数 + /// + /// 获取ID + /// + /// + public long NextID() + { + lock (this) + { + long timestamp = timeGen(); + if (m_lastTimestamp == timestamp) + { //同一微妙中生成ID + Sequence = (Sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限 + if (Sequence == 0) + { + //一微妙内产生的ID计数已达上限,等待下一微妙 + timestamp = tillNextMillis(m_lastTimestamp); + } + } + else + { //不同微秒生成ID + Sequence = 0; //计数清0 + } + if (timestamp < m_lastTimestamp) + { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过 + throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", + m_lastTimestamp - timestamp)); + } + m_lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳 + long nextId = (timestamp - Twepoch << TimestampLeftShift) | WorkerId << WorkerIdShift | Sequence; + return nextId; + } + } + + /// + /// 获取下一微秒时间戳 + /// + /// + /// + private long tillNextMillis(long lastTimestamp) + { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) + { + timestamp = timeGen(); + } + return timestamp; + } + + /// + /// 生成当前时间戳 + /// + /// + private long timeGen() + { + return Environment.TickCount; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs.meta new file mode 100644 index 0000000..c0b229b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e135284191009d4899cf9a10724ed4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs new file mode 100644 index 0000000..e38ae69 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.ComponentModel; + +namespace TouchSocket.Core +{ + /// + /// 字符串资源字典 + /// + public static class StringResStore + { + private static readonly ConcurrentDictionary m_cache = new ConcurrentDictionary(); + + /// + /// 获取资源字符 + /// + /// + /// + /// + public static string GetDescription(this Enum @enum, params object[] objs) + { + if (m_cache.TryGetValue(@enum, out string str)) + { + if (string.IsNullOrEmpty(str)) + { + return @enum.ToString(); + } + else + { + return str.Format(objs); + } + } + + if (@enum.GetAttribute() is DescriptionAttribute description) + { + string res = description.Description; + m_cache.TryAdd(@enum, res); + if (!string.IsNullOrEmpty(res)) + { + if (objs.Length > 0) + { + return res.Format(objs); + } + else + { + return res; + } + } + } + return @enum.ToString(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs.meta new file mode 100644 index 0000000..ef9cb74 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/StringResStore.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b106c282625b7d944a2649deeca72572 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs new file mode 100644 index 0000000..030e783 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//using System; +//using System.Collections.Concurrent; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; + +//namespace TouchSocket.Core +//{ +// /// +// /// 异常助手 +// /// +// public static class ThrowHelper +// { +// private static readonly ConcurrentDictionary> m_pairs = +// new ConcurrentDictionary>(); + +// /// +// /// 添加抛出规则。 +// /// +// /// +// /// +// public static void Add(Enum @enum,Func func) +// { +// if (@enum is null) +// { +// throw new ArgumentNullException(nameof(@enum)); +// } + +// if (func is null) +// { +// throw new ArgumentNullException(nameof(func)); +// } + +// m_pairs.TryRemove(@enum,out _); +// m_pairs.TryAdd(@enum,func); +// } + +// public static Exception Throw(Enum @enum,string msg,Exception exception) +// { +// } + +// } +//} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs.meta new file mode 100644 index 0000000..0109087 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/ThrowHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c0339e4483e66449b1fc78aff0e39e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs new file mode 100644 index 0000000..7814449 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs @@ -0,0 +1,498 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Runtime.CompilerServices; + +namespace TouchSocket.Core +{ + /// + /// 将基数据类型转换为指定端的一个字节数组, + /// 或将一个字节数组转换为指定端基数据类型。 + /// + public class TouchSocketBitConverter + { + /// + /// 以大端 + /// + public static TouchSocketBitConverter BigEndian; + + /// + /// 以小端 + /// + public static TouchSocketBitConverter LittleEndian; + + static TouchSocketBitConverter() + { + BigEndian = new TouchSocketBitConverter(EndianType.Big); + LittleEndian = new TouchSocketBitConverter(EndianType.Little); + DefaultEndianType = EndianType.Little; + } + + private static TouchSocketBitConverter m_default; + + /// + /// 以默认小端,可通过重新指定默认端。 + /// + public static TouchSocketBitConverter Default => m_default; + + private static EndianType m_defaultEndianType; + + /// + /// 默认大小端切换。 + /// + public static EndianType DefaultEndianType + { + get => m_defaultEndianType; + set + { + m_defaultEndianType = value; + switch (value) + { + case EndianType.Little: + m_default = LittleEndian; + break; + + case EndianType.Big: + m_default = BigEndian; + break; + + default: + break; + } + } + } + + private readonly EndianType endianType; + + /// + /// 构造函数 + /// + /// + public TouchSocketBitConverter(EndianType endianType) + { + this.endianType = endianType; + } + + /// + /// 指定大小端。 + /// + public EndianType EndianType => endianType; + + /// + /// 判断当前系统是否为设置的大小端 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSameOfSet() + { + return !(BitConverter.IsLittleEndian ^ (endianType == EndianType.Little)); + //return true; + } + + #region ushort + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(ushort value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + return bytes; + } + + /// + /// 转换为指定端模式的2字节转换为UInt16数据。 + /// + /// + /// + /// + public ushort ToUInt16(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt16(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, 2); + Array.Reverse(bytes); + return BitConverter.ToUInt16(bytes, 0); + } + } + + #endregion ushort + + #region ulong + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(ulong value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Ulong数据。 + /// + /// + /// + /// + public ulong ToUInt64(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt64(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, 8); + Array.Reverse(bytes); + return BitConverter.ToUInt64(bytes,0); + } + + } + + #endregion ulong + + #region bool + + /// + /// 转换为指定端1字节 + /// + /// + /// + public byte[] GetBytes(bool value) + { + return BitConverter.GetBytes(value); + } + + /// + /// 转换为指定端模式的bool数据。 + /// + /// + /// + /// + public bool ToBoolean(byte[] buffer, int offset) + { + return BitConverter.ToBoolean(buffer, offset); + } + + #endregion bool + + #region char + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(char value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Char数据。 + /// + /// + /// + /// + public char ToChar(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToChar(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToChar(bytes, 0); + } + } + + #endregion char + + #region short + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(short value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Short数据。 + /// + /// + /// + /// + public short ToInt16(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt16(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt16(bytes, 0); + } + + } + + #endregion short + + #region int + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(int value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的int数据。 + /// + /// + /// + /// + public int ToInt32(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt32(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt32(bytes, 0); + } + } + + #endregion int + + #region long + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(long value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的long数据。 + /// + /// + /// + /// + public long ToInt64(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt64(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt64(bytes, 0); + } + + } + + #endregion long + + #region uint + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(uint value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Uint数据。 + /// + /// + /// + /// + public uint ToUInt32(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt32(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToUInt32(bytes, 0); + } + } + + #endregion uint + + #region float + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的float数据。 + /// + /// + /// + /// + public float ToSingle(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToSingle(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToSingle(bytes, 0); + } + } + + #endregion float + + #region long + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(double value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的double数据。 + /// + /// + /// + /// + public double ToDouble(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToDouble(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToDouble(bytes, 0); + } + } + + #endregion long + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs.meta new file mode 100644 index 0000000..216b869 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketBitConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bea05cf50d8689d479961b412b0a5137 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs new file mode 100644 index 0000000..c5a7dcf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; + +namespace TouchSocket.Core +{ + /// + /// 常量 + /// + public class TouchSocketCoreUtility + { +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + public static readonly Type stringType = typeof(string); + public static readonly Type byteType = typeof(byte); + public static readonly Type sbyteType = typeof(sbyte); + public static readonly Type shortType = typeof(short); + public static readonly Type objType = typeof(object); + public static readonly Type ushortType = typeof(ushort); + public static readonly Type intType = typeof(int); + public static readonly Type uintType = typeof(uint); + public static readonly Type boolType = typeof(bool); + public static readonly Type charType = typeof(char); + public static readonly Type longType = typeof(long); + public static readonly Type ulongType = typeof(ulong); + public static readonly Type floatType = typeof(float); + public static readonly Type doubleType = typeof(double); + public static readonly Type decimalType = typeof(decimal); + public static readonly Type dateTimeType = typeof(DateTime); + public static readonly Type bytesType = typeof(byte[]); + public static readonly Type dicType = typeof(IDictionary); + public static readonly Type iEnumerableType = typeof(IEnumerable); + public static readonly Type arrayType = typeof(Array); + public static readonly Type listType = typeof(IList); + public static readonly Type nullableType = typeof(Nullable<>); + + public static readonly byte[] ZeroBytes = new byte[0]; +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs.meta new file mode 100644 index 0000000..57118b8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/TouchSocketCoreUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ecf953fa94ffec741931af4e78e51aa9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config.meta new file mode 100644 index 0000000..30ce7c5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a90b867395e0ee04bba859a9d1e1bf21 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs new file mode 100644 index 0000000..1653c76 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 配置文件基类 + /// + public class TouchSocketConfig : DependencyObject + { + //private bool built; + private IContainer m_container; + + private IPluginsManager m_pluginsManager; + + //ConcurrentQueue> actions = new ConcurrentQueue>(); + + ///// + ///// 添加构建委托,该委托会在时调用。 + ///// + ///// + ///// + //public void AddBuildAction(Delegate action,params object[] ps) + //{ + // actions.Enqueue(Tuple.Create(action,ps)) ; + //} + + ///// + ///// 构建配置 + ///// + //public void Build() + //{ + // if (!built) + // { + // built = true; + // while (actions.TryDequeue(out var action)) + // { + // action.Item1.DynamicInvoke(action.Item2); + // } + // } + //} + + /// + /// 构造函数 + /// + public TouchSocketConfig() + { + SetContainer(new Container()); + } + + /// + /// IOC容器。 + /// + public IContainer Container => m_container; + + /// + /// 使用插件 + /// + public bool IsUsePlugin { get; set; } + + /// + /// 插件管理器 + /// + public IPluginsManager PluginsManager => m_pluginsManager; + + /// + /// 设置注入容器。 + /// + /// + /// + public TouchSocketConfig SetContainer(IContainer value) + { + m_container = value; + if (!value.IsRegistered(typeof(ILog))) + { + m_container.RegisterSingleton(); + } + SetPluginsManager(new PluginsManager(m_container)); + return this; + } + + /// + /// 设置PluginsManager + /// + /// + /// + public TouchSocketConfig SetPluginsManager(IPluginsManager value) + { + m_pluginsManager = value; + m_container.RegisterSingleton(value); + return this; + } + + /// + /// 启用插件 + /// + /// + public TouchSocketConfig UsePlugin() + { + IsUsePlugin = true; + return this; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs.meta new file mode 100644 index 0000000..bb62749 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d745c7bb315fa44ea5f11136c4a0993 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs new file mode 100644 index 0000000..2c625bb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// TouchSocketCoreConfigExtension + /// + public static class TouchSocketCoreConfigExtension + { + #region 插件 + + /// + /// 配置插件。 + /// + /// + /// + /// + public static TouchSocketConfig ConfigurePlugins(this TouchSocketConfig config, Action action) + { + action?.Invoke(config.PluginsManager); + return config; + } + + #endregion 插件 + + #region 容器 + + /// + /// 配置容器注入。 + /// + /// + /// + /// + public static TouchSocketConfig ConfigureContainer(this TouchSocketConfig config, Action action) + { + action?.Invoke(config.Container); + return config; + } + + #endregion 容器 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs.meta new file mode 100644 index 0000000..db6f2e9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62feb3bbf0c32a84688d1e05cd4fb36b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter.meta new file mode 100644 index 0000000..79b45b8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c5e981e4651cd34faddbe786967c0df +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs new file mode 100644 index 0000000..815e7d5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// 字节类转换器 + /// + public class BytesConverter : TouchSocketConverter + { + /// + /// 字节类转换器 + /// + public BytesConverter() + { + Add(new JsonBytesToClassConverter()); + } + } + + /// + /// Json字节转到对应类 + /// + public class JsonBytesToClassConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(byte[] source, Type targetType, out object target) + { + try + { + target = SerializeConvert.JsonDeserializeFromBytes(source, targetType); + return true; + } + catch + { + target = default; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out byte[] source) + { + try + { + source = SerializeConvert.JsonSerializeToBytes(target); + return true; + } + catch (Exception) + { + source = null; + return false; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs.meta new file mode 100644 index 0000000..67d2f1b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/BytesConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16262141474d2ba43a5af513cc358d38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs new file mode 100644 index 0000000..82f2c5e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 转换器接口 + /// + public interface IConverter + { + /// + /// 转换器执行顺序 + /// 该属性值越小,越靠前执行。值相等时,按添加先后顺序 + /// 该属性效果,仅在之前设置有效。 + /// + int Order { get; set; } + + /// + /// 尝试将源数据转换目标类型对象 + /// + /// + /// + /// + /// + bool TryConvertFrom(TSource source, Type targetType, out object target); + + /// + /// 尝试将目标类型对象转换源数据 + /// + /// + /// + /// + bool TryConvertTo(object target, out TSource source); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs.meta new file mode 100644 index 0000000..45d8189 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/IConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04776187b8628254daac77c59b82c12e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs new file mode 100644 index 0000000..e1efe5c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// String类型数据转换器 + /// + public class StringConverter : TouchSocketConverter + { + /// + /// 构造函数 + /// + public StringConverter() + { + Add(new StringToPrimitiveConverter()); + Add(new JsonStringToClassConverter()); + } + } + + /// + /// String值转换为基础类型。 + /// + public class StringToPrimitiveConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(string source, Type targetType, out object target) + { + if (targetType.IsPrimitive || targetType == TouchSocketCoreUtility.stringType) + { + return StringExtension.TryParseToType(source, targetType, out target); + } + target = default; + return false; + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out string source) + { + if (target != null) + { + Type type = target.GetType(); + if (type.IsPrimitive || type == TouchSocketCoreUtility.stringType) + { + source = target.ToString(); + return true; + } + } + + source = null; + return false; + } + } + + /// + /// Json字符串转到对应类 + /// + public class JsonStringToClassConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(string source, Type targetType, out object target) + { + try + { + target = source.FromJson(targetType); + return true; + } + catch + { + target = default; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out string source) + { + try + { + source = target.ToJson(); + return true; + } + catch (Exception) + { + source = null; + return false; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs.meta new file mode 100644 index 0000000..85f7386 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/StringConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f8ea2d12952ed4b4185ca409d9264c1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs new file mode 100644 index 0000000..0429250 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 转换器 + /// + public class TouchSocketConverter + { + private readonly List> m_converters = new List>(); + + /// + /// 添加插件 + /// + /// 插件 + /// + public void Add(IConverter converter) + { + if (converter == null) + { + throw new ArgumentNullException(); + } + foreach (var item in m_converters) + { + if (item.GetType() == converter.GetType()) + { + return; + } + } + + m_converters.Add(converter); + + m_converters.Sort(delegate (IConverter x, IConverter y) + { + if (x.Order == y.Order) return 0; + else if (x.Order > y.Order) return 1; + else return -1; + }); + } + + /// + /// 清除所有转化器 + /// + public void Clear() + { + m_converters.Clear(); + } + + /// + /// 将源数据转换目标类型对象 + /// + /// + /// + /// + public object ConvertFrom(TSource source, Type targetType) + { + object result; + foreach (var item in m_converters) + { + if (item.TryConvertFrom(source, targetType, out result)) + { + return result; + } + } + + throw new Exception($"{source}无法转换为{targetType}类型。"); + } + + /// + /// 将目标类型对象转换源数据 + /// + /// + /// + public TSource ConvertTo(object target) + { + foreach (var item in m_converters) + { + if (item.TryConvertTo(target, out TSource source)) + { + return source; + } + } + + throw new Exception($"{target}无法转换为{typeof(TSource)}类型。"); + } + + /// + /// 移除插件 + /// + /// + public void Remove(IConverter converter) + { + if (converter == null) + { + throw new ArgumentNullException(); + } + m_converters.Remove(converter); + } + + /// + /// 移除插件 + /// + /// + public void Remove(Type type) + { + for (int i = m_converters.Count - 1; i >= 0; i--) + { + IConverter plugin = m_converters[i]; + if (plugin.GetType() == type) + { + m_converters.RemoveAt(i); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs.meta new file mode 100644 index 0000000..55c69b3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Converter/TouchSocketConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 384b828fa71e91e4d9ee0cb4432bfe06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data.meta new file mode 100644 index 0000000..3f6895e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aaa6b283fc4661240b7860df0186461c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress.meta new file mode 100644 index 0000000..4a13f53 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ff8ffd48c6c8ef4eabc9531eba8db1f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs new file mode 100644 index 0000000..37d79ea --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// GZip压缩算法的压缩机 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public sealed partial class GZipDataCompressor : IDataCompressor + { + byte[] IDataCompressor.Compress(ArraySegment data) + { + return GZip.Compress(data.Array, data.Offset, data.Count); + } + + byte[] IDataCompressor.Decompress(ArraySegment data) + { + return GZip.Decompress(data.Array, data.Offset, data.Count); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs.meta new file mode 100644 index 0000000..218e3e0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c1d03417dc351149b31434be6f53bdd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs new file mode 100644 index 0000000..16de22f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 数据压缩机接口 + /// + public interface IDataCompressor + { + /// + /// 压缩数据 + /// + /// + /// + byte[] Compress(ArraySegment data); + + /// + /// 解压数据 + /// + /// + /// + byte[] Decompress(ArraySegment data); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs.meta new file mode 100644 index 0000000..0db12b6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Compress/IDataCompressor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09b30440142fbf54da8c38270dc2835b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs new file mode 100644 index 0000000..7f18dc8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs @@ -0,0 +1,783 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// Crc相关。 + /// 该代码来源于网络 + /// + public static class Crc + { + /// ********************************************************************** + /// Name: CRC-4/ITU x4+x+1 + /// Poly: 0x03 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc1(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x0C);//0x0C = (reverse 0x03)>>(8-4) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-5/EPC x5+x3+1 + /// Poly: 0x09 + /// Init: 0x09 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc2(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0x48;// Initial value: 0x48 = 0x09<<(8-5) + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x48);// 0x48 = 0x09<<(8-5) + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc >> 3) }; + } + + /// ********************************************************************** + /// Name: CRC-5/ITU x5+x4+x2+1 + /// Poly: 0x15 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc3(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x15);// 0x15 = (reverse 0x15)>>(8-5) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-5/USB x5+x2+1 + /// Poly: 0x05 + /// Init: 0x1F + /// Refin: true + /// Refout: true + /// Xorout: 0x1F + ///************************************************************************* + public static byte[] Crc4(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0x1F;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x14);// 0x14 = (reverse 0x05)>>(8-5) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { (byte)(crc ^ 0x1F) }; + } + + /// ********************************************************************** + /// Name: CRC-6/ITU x6+x+1 + /// Poly: 0x03 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc5(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x30);// 0x30 = (reverse 0x03)>>(8-6) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-7/MMC x7+x3+1 + /// Poly: 0x09 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc6(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x12);// 0x12 = 0x09<<(8-7) + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc >> 1) }; + } + + /// ********************************************************************** + /// Name: CRC8 x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc7(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x07); + else + crc = (byte)(crc << 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-8/ITU x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x55 + ///************************************************************************* + public static byte[] Crc8(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x07); + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc ^ 0x55) }; + } + + /// ********************************************************************** + /// Name: CRC-8/MAXIM x8+x5+x4+1 + /// Poly: 0x31 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc9(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x8C);// 0x8C = reverse 0x31 + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-8/ROHC x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0xFF + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc10(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0xFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0xE0);// 0xE0 = reverse 0x07 + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// Z1协议校验码计算 + private static readonly byte[] table = { 0x00, 0x1C, 0x38, 0x24, 0x70, 0x6C, 0x48, 0x54, 0xE0, 0xFC, + 0xD8, 0xC4, 0x90, 0x8C, 0xA8, 0xB4, 0xDC, 0xC0, 0xE4, 0xF8, + 0xAC, 0xB0, 0x94, 0x88, 0x3C, 0x20, 0x04, 0x18, 0x4C, 0x50, + 0x74, 0x68, 0xA4, 0xB8, 0x9C, 0x80, 0xD4, 0xC8, 0xEC, 0xF0, + 0x44, 0x58, 0x7C, 0x60, 0x34, 0x28, 0x0C, 0x10, 0x78, 0x64, + 0x40, 0x5C, 0x08, 0x14, 0x30, 0x2C, 0x98, 0x84, 0xA0, 0xBC, + 0xE8, 0xF4, 0xD0, 0xCC, 0x54, 0x48, 0x6C, 0x70, 0x24, 0x38, + 0x1C, 0x00, 0xB4, 0xA8, 0x8C, 0x90, 0xC4, 0xD8, 0xFC, 0xE0, + 0x88, 0x94, 0xB0, 0xAC, 0xF8, 0xE4, 0xC0, 0xDC, 0x68, 0x74, + 0x50, 0x4C, 0x18, 0x04, 0x20, 0x3C, 0xF0, 0xEC, 0xC8, 0xD4, + 0x80, 0x9C, 0xB8, 0xA4, 0x10, 0x0C, 0x28, 0x34, 0x60, 0x7C, + 0x58, 0x44, 0x2C, 0x30, 0x14, 0x08, 0x5C, 0x40, 0x64, 0x78, + 0xCC, 0xD0, 0xF4, 0xE8, 0xBC, 0xA0, 0x84, 0x98, 0xA8, 0xB4, + 0x90, 0x8C, 0xD8, 0xC4, 0xE0, 0xFC, 0x48, 0x54, 0x70, 0x6C, + 0x38, 0x24, 0x00, 0x1C, 0x74, 0x68, 0x4C, 0x50, 0x04, 0x18, + 0x3C, 0x20, 0x94, 0x88, 0xAC, 0xB0, 0xE4, 0xF8, 0xDC, 0xC0, + 0x0C, 0x10, 0x34, 0x28, 0x7C, 0x60, 0x44, 0x58, 0xEC, 0xF0, + 0xD4, 0xC8, 0x9C, 0x80, 0xA4, 0xB8, 0xD0, 0xCC, 0xE8, 0xF4, + 0xA0, 0xBC, 0x98, 0x84, 0x30, 0x2C, 0x08, 0x14, 0x40, 0x5C, + 0x78, 0x64, 0xFC, 0xE0, 0xC4, 0xD8, 0x8C, 0x90, 0xB4, 0xA8, + 0x1C, 0x00, 0x24, 0x38, 0x6C, 0x70, 0x54, 0x48, 0x20, 0x3C, + 0x18, 0x04, 0x50, 0x4C, 0x68, 0x74, 0xC0, 0xDC, 0xF8, 0xE4, + 0xB0, 0xAC, 0x88, 0x94, 0x58, 0x44, 0x60, 0x7C, 0x28, 0x34, + 0x10, 0x0C, 0xB8, 0xA4, 0x80, 0x9C, 0xC8, 0xD4, 0xF0, 0xEC, + 0x84, 0x98, 0xBC, 0xA0, 0xF4, 0xE8, 0xCC, 0xD0, 0x64, 0x78, + 0x5C, 0x40, 0x14, 0x08, 0x2C, 0x30 + }; + + /// + /// Crc11 + /// + /// + /// + /// + /// + public static byte[] Crc11(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + int i; + byte crc = 0x00; + int tableIndex; + for (i = start; i < length; i++) + { + tableIndex = crc ^ (buffer[i] & 0xFF); + crc = table[tableIndex]; + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-12 x16+x12+x5+1 + /// Poly: 0x80 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc12(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + short iQ = 0, iR = 0; + for (int i = start; i < length; i++) + { + // 多项式除法 + // 如果该位为1 + if ((buffer[i] & (0x80 >> iR)) > 0) + { + // 则在余数尾部添1否则添0 + crc |= 0x01; + } + // 如果12位除数中的最高位为1,则够除 + if (crc >= 0x1000) + { + crc ^= 0x180D; + } + crc <<= 1; + iR++; + if (8 == iR) + { + iR = 0; + iQ++; + } + } + // 对后面添加的12个0做处理 + for (int i = 0; i < 12; i++) + { + if (crc >= 0x1000) + { + crc ^= 0x180D; + } + crc <<= 1; + } + crc >>= 1; + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/CCITT x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc13(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0x8408);// 0x8408 = reverse 0x1021 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/CCITT FALSE x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0xFFFF + /// Refin: false + /// Refout: false + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc14(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (ushort)(buffer[i] << 8); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x8000) > 0) + crc = (ushort)((crc << 1) ^ 0x1021); + else + crc = (ushort)(crc << 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/DNP x16+x13+x12+x11+x10+x8+x6+x5+x2+1 + /// Poly: 0x3D65 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc15(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA6BC);// 0xA6BC = reverse 0x3D65 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/IBM x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc16(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/MAXIM x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc17(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/MODBUS x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc18(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/USB x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc19(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/X25 x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc20(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0x8408);// 0x8408 = reverse 0x1021 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/XMODEM x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0x0000 + /// Refin: false + /// Refout: false + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc21(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (ushort)(buffer[i] << 8); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x8000) > 0) + crc = (ushort)((crc << 1) ^ 0x1021); + else + crc = (ushort)(crc << 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + /// Poly: 0x04C11DB7 + /// Init: 0xFFFFFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFFFFFF + ///************************************************************************* + public static byte[] Crc22(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + uint crc = 0xFFFFFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7 + else + crc = crc >> 1; + } + } + byte[] ret = BitConverter.GetBytes(~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC32/MPEG-2 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + /// Poly: 0x04C11DB7 + /// Init: 0xFFFFFFFF + /// Refin: false + /// Refout: false + /// Xorout: 0x00000000 + ///************************************************************************* + public static byte[] Crc23(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + uint crc = 0xFFFFFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (uint)(buffer[i] << 24); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80000000) > 0) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc = crc << 1; + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs.meta new file mode 100644 index 0000000..31b9d8b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Crc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61728e0d09f0d0b4881534632e5c06b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs new file mode 100644 index 0000000..f9a34c5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using System.IO.Compression; + +namespace TouchSocket.Core +{ + /// + /// Gzip操作类 + /// + public static class GZip + { + /// + /// 压缩数据 + /// + /// + /// + /// + /// + /// + public static void Compress(ByteBlock byteBlock, byte[] buffer, int offset, int length) + { + using (GZipStream gZipStream = new GZipStream(byteBlock, CompressionMode.Compress, true)) + { + gZipStream.Write(buffer, offset, length); + gZipStream.Close(); + } + } + + /// + /// 压缩数据 + /// + /// + /// + /// + public static void Compress(ByteBlock byteBlock, byte[] buffer) + { + Compress(byteBlock, buffer, 0, buffer.Length); + } + + /// + /// 压缩数据 + /// + /// + /// + /// + /// + public static byte[] Compress(byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length)) + { + Compress(byteBlock, buffer, offset, length); + return byteBlock.ToArray(); + } + } + + /// + /// 压缩数据 + /// + /// + /// + public static byte[] Compress(byte[] buffer) + { + return Compress(buffer, 0, buffer.Length); + } + + /// + /// 解压数据 + /// + /// + /// + /// + /// + /// + public static void Decompress(ByteBlock byteBlock, byte[] data, int offset, int length) + { + using (GZipStream gZipStream = new GZipStream(new MemoryStream(data, offset, length), CompressionMode.Decompress)) + { + byte[] bytes = BytePool.Default.GetByteCore(1024 * 64); + try + { + int r; + while ((r = gZipStream.Read(bytes, 0, bytes.Length)) != 0) + { + byteBlock.Write(bytes, 0, r); + } + gZipStream.Close(); + } + finally + { + BytePool.Default.Recycle(bytes); + } + } + } + + /// + /// 解压数据 + /// + /// + /// + public static void Decompress(ByteBlock byteBlock, byte[] data) + { + Decompress(byteBlock, data, 0, data.Length); + } + + /// + /// 解压数据 + /// + /// + /// + /// + /// + public static byte[] Decompress(byte[] data, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length)) + { + Decompress(byteBlock, data, offset, length); + return byteBlock.ToArray(); + } + } + + /// + /// 解压数据 + /// + /// + /// + public static byte[] Decompress(byte[] data) + { + return Decompress(data, 0, data.Length); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs.meta new file mode 100644 index 0000000..69d503f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/GZip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c0e9eb824ba23a42a12ed5233e10614 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs new file mode 100644 index 0000000..c5e7f4f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// MD5相关操作类 + /// + public static class MD5 + { + /// + /// 从字符串获取MD5值 + /// + /// + /// + public static string GetMD5Hash(string str) + { + StringBuilder sb = new StringBuilder(); + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); + int length = data.Length; + for (int i = 0; i < length; i++) + sb.Append(data[i].ToString("X2")); + } + return sb.ToString(); + } + + /// + /// 从字节获取MD5值 + /// + /// + /// + /// + /// + public static string GetMD5Hash(byte[] buffer, int offset, int length) + { + StringBuilder sb = new StringBuilder(); + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + byte[] data = md5.ComputeHash(buffer, offset, length); + int count = data.Length; + for (int i = 0; i < count; i++) + sb.Append(data[i].ToString("X2")); + } + return sb.ToString(); + } + + /// + /// 从字节获取MD5值 + /// + /// + /// + public static string GetMD5Hash(byte[] buffer) + { + return GetMD5Hash(buffer, 0, buffer.Length); + } + + /// + /// 验证MD5值。 + /// + /// + /// + /// + public static bool VerifyMD5Hash(string str, string hash) + { + string hashOfInput = GetMD5Hash(str); + if (hashOfInput.CompareTo(hash) == 0) + return true; + else + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs.meta new file mode 100644 index 0000000..285e4ec --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/MD5.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: edec659c1bffaa4468b41a6d21441184 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security.meta new file mode 100644 index 0000000..e0eb51e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 000311fda1a11324fb963fe274b2a18a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs new file mode 100644 index 0000000..c09011a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 数据安全加密 + /// + public static class DataSecurity + { + /// + /// 自定义加密密钥。 + /// + private static byte[] Keys { get; set; } = { 0x12, 0x34, 4, 0x78, 0x90, 255, 0xCD, 0xEF };//自定义密匙 + + /// + /// 使用3DES加密 + /// + /// 待加密字节 + /// 加密口令(长度为8) + /// + public static byte[] EncryptDES(byte[] data, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + using (var des = DES.Create()) + { + using (MemoryStream mStream = new MemoryStream()) + { + using (CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(rgbKey, Keys), CryptoStreamMode.Write)) + { + cStream.Write(data, 0, data.Length); + cStream.FlushFinalBlock(); + return mStream.ToArray(); + } + } + } + } + + /// + /// 使用3DES解密 + /// + /// 待解密字节 + /// 解密口令(长度为8) + /// + public static byte[] DecryptDES(byte[] data, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey); + using (var des = DES.Create()) + { + using (MemoryStream mStream = new MemoryStream()) + { + using (CryptoStream cStream = new CryptoStream(mStream, des.CreateDecryptor(rgbKey, Keys), CryptoStreamMode.Write)) + { + cStream.Write(data, 0, data.Length); + cStream.FlushFinalBlock(); + return mStream.ToArray(); + } + } + } + } + + /// + /// 使用3DES流数据加密。 + /// 注意:数据会从开始 + /// + /// + /// + /// 加密口令(长度为8) + /// + public static void StreamEncryptDES(Stream inStream, Stream outStream, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKeys = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] byteIn = new byte[1024 * 64]; + long readLen = 0; + long totalLen = inStream.Length - inStream.Position; + using (var des = DES.Create()) + { + CryptoStream encStream = new CryptoStream(new WrapStream(outStream), des.CreateEncryptor(rgbKeys, Keys), CryptoStreamMode.Write); + while (readLen < totalLen) + { + int r = inStream.Read(byteIn, 0, byteIn.Length); + encStream.Write(byteIn, 0, r); + readLen += r; + } + encStream.Close(); + } + } + + /// + /// 使用3DES流数据解密 + /// 注意:数据会从开始 + /// + /// + /// + /// 解密口令(长度为8) + public static void StreamDecryptDES(Stream inStream, Stream outStream, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKeys = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] byteIn = new byte[1024 * 64]; + long readLen = 0; + long totalLen = inStream.Length - inStream.Position; + using (DES des = DES.Create()) + { + CryptoStream encStream = new CryptoStream(new WrapStream(outStream), des.CreateDecryptor(rgbKeys, Keys), CryptoStreamMode.Write); + while (readLen < totalLen) + { + int r = inStream.Read(byteIn, 0, byteIn.Length); + encStream.Write(byteIn, 0, r); + readLen = readLen + r; + } + encStream.Close(); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs.meta new file mode 100644 index 0000000..cd79edc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Security/DataSecurity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac359c46b20a0a14c9253723a9aa618d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs new file mode 100644 index 0000000..e9cc583 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 交换类。功能类似:a=1,b=2,交换后a=2,b=1。 + /// + public static class Swap + { + /// + /// 执行交换 + /// + /// + /// + /// + public static void Execute(ref T x, ref T y) + { +#if NET45_OR_GREATER + T temp = x; + x = y; + y = temp; +#else + (y, x) = (x, y); +#endif + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs.meta new file mode 100644 index 0000000..372e66b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/Swap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13fb227600bfa314988e0d8224aafded +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML.meta new file mode 100644 index 0000000..e49e95e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 19363b92b4b128044afdb710b47930f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs new file mode 100644 index 0000000..764fa65 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs @@ -0,0 +1,721 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace TouchSocket.Core +{ + /// + /// xml主类 + /// + public class XmlTool + { + /// + /// 构造函数 + /// + /// 文件路径,包含文件名 + public XmlTool(string path) + { + this.path = path; + } + + private readonly string path = null; + + #region 存储 + + /// + /// 单节点,单属性储存 + /// + /// 节点名 + /// 属性名 + /// 属性值 + public void AttributeStorage(string NodeName, string Attribute_name, string Attribute_value) + { + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool N = false;//节点判断变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName); + PointName.SetAttribute(Attribute_name, Attribute_value); + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + PointName.Attributes[Attribute_name].Value = Attribute_value; + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + + XmlElement PointName = xml.CreateElement(NodeName); + PointName.SetAttribute(Attribute_name, Attribute_value); + root.AppendChild(PointName); + xml.Save(path); + } + } + + /// + /// 单节点,多属性存储 + /// + /// 节点名 + /// 属性集合 + /// 属性值集合 + public void AttributeStorage(string NodeName, string[] Attribute_name, string[] Attribute_value) + { + if (Attribute_name.Length != Attribute_value.Length) + { + Console.WriteLine("属性名数量和属性值数量不一致,无法储存"); + return; + } + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i]; + } + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + + XmlElement PointName = xml.CreateElement(NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + xml.Save(path); + } + } + + /// + /// 单节点,单属性多集合存储 + /// + /// 节点集合 + /// 属性名集合 + /// 属性值集合 + public void AttributeStorage(string[] NodeName, string[] Attribute_name, string[] Attribute_value) + { + if ((Attribute_name.Length != Attribute_value.Length) && NodeName.Length != Attribute_name.Length) + { + Console.WriteLine("属性名数量和属性值数量不一致,无法储存"); + return; + } + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName[i]) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName[i]); + + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + + PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i]; + } + xml.Save(path); + } + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + for (int i = 0; i < NodeName.Length; i++) + { + XmlElement PointName = xml.CreateElement(NodeName[i]); + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + + xml.Save(path); + } + } + } + + /// + /// 多节点,多属性,多集合存储 + /// + /// 节点集合 + /// 属性集合 + /// 每个节点的属性数量 + /// 属性值集合 + public void AttributeStorage(string[] NodeName, string[] Attribute_name, int AttributeNumber, params string[][] Attribute_value) + { + if (File.Exists(path)) + { + //存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName[i]) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName[i]); + for (int j = 0; j < AttributeNumber; j++) + { + PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]); + } + + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName[i]); + + for (int j = 0; j < AttributeNumber; j++) + { + PointName.Attributes[Attribute_name[j]].Value = Attribute_value[j][i]; + } + } + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + for (int i = 0; i < NodeName.Length; i++) + { + XmlElement PointName = xml.CreateElement(NodeName[i]); + for (int j = 0; j < AttributeNumber; j++) + { + PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]); + } + root.AppendChild(PointName); + + xml.Save(path); + } + } + } + + /// + /// 节点值存储 + /// + /// 节点名 + /// 文本 + public void NodeStorage(string NodeName, string Text) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool n = false; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + item.InnerText = Text; + n = true; + break; + } + } + if (n == false) + { + XmlElement other = xml.CreateElement(NodeName); + other.InnerText = Text; + root.AppendChild(other); + } + xml.Save(path); + } + else + { + XmlDocument doc = new XmlDocument(); + XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement Root = doc.CreateElement("Root"); + doc.AppendChild(Root);//根元素 + + XmlElement Node = doc.CreateElement(NodeName); + Node.InnerText = Text; + Root.AppendChild(Node); + + doc.Save(path); + } + } + + #endregion 存储 + + #region + + /// + /// 通过节点取值 + /// + /// 节点名 + /// 取值失败返回null + public string SearchNode(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + return item.InnerText; + } + } + } + return null; + } + + /// + /// 查找数字 + /// + /// 节点名 + /// 属性名 + /// 取值失败返回0 + public int SearchNumber(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + return Convert.ToInt32(item.Attributes[Attribute_name].Value); + } + } + } + } + return 0; + } + + /// + /// 查找属性值 + /// + /// 节点名 + /// 属性名 + /// 取值失败返回null + public string SearchWords(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + return item.Attributes[Attribute_name].Value; + } + } + } + } + return null; + } + + /// + /// 查找布尔值 + /// + /// 节点名 + /// 属性值 + /// 返回查找结果,查询失败返回false + public bool SearchBoolean(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + try + { + return Convert.ToBoolean(item.Attributes[Attribute_name].Value); + } + catch + { + return false; + } + } + } + } + } + return false; + } + + /// + /// 查找属性值集合 + /// + /// 节点名集合 + /// 属性名集合 + /// 文件不在返回null,单个属性不在返回“空” + public string[] SearchWords(string[] NodeName, string[] Attribute_name) + { + if (File.Exists(path)) + { + string[] s = new string[NodeName.Length]; + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName[i]) + { + if (item.Attributes[Attribute_name[i]] != null) + { + s[i] = item.Attributes[Attribute_name[i]].Value; + } + else + { + s[i] = ""; + } + } + } + } + return s; + } + return null; + } + + /// + /// 通过确切属性值,属性名,查找其他属性值 + /// + /// 已知属性名 + /// 已知属性值 + /// 待查属性名 + /// 待查属性值 + public string[] SearchWords(string Attribute_name1, string Attribute_value, string Attribute_name2) + { + List values = new List(); + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name1] != null) + { + if (item.Attributes[Attribute_name1].Value == Attribute_value) + { + if (item.Attributes[Attribute_name2] != null) + { + values.Add(item.Attributes[Attribute_name2].Value); + } + } + } + } + } + return values.ToArray(); + } + + /// + /// 查找节点的所有属性值 + /// + /// 节点 名 + /// 返回查找键值对,查询失败返回null + public Dictionary SearchAllAttributes(string NodeName) + { + Dictionary Attributes = new Dictionary(); + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + XmlAttributeCollection attributeCollection = item.Attributes; + if (attributeCollection != null) + { + foreach (XmlAttribute attribute in attributeCollection) + { + Attributes.Add(attribute.Name, attribute.Value); + } + } + return Attributes; + } + } + } + return null; + } + + /// + /// 通过确切属性值,属性名,查找其他属性的布尔值 + /// + /// 已知属性名 + /// 已知属性值 + /// 待查属性名 + /// 待查布尔值,失败返回false + public bool SearchBoolean(string Attribute_name1, string Attribute_value, string Attribute_name2) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name1].Value == Attribute_value) + { + if (item.Attributes[Attribute_name2] != null) + { + try + { + return Convert.ToBoolean(item.Attributes[Attribute_name2].Value); + } + catch + { + return false; + } + } + } + } + } + return false; + } + + #endregion + + /// + /// 按节点名移除节点 + /// + /// 节点名 + /// 是否移除成功 + public bool RemoveNode(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + root.RemoveChild(item); + xml.Save(path); + return true; + } + } + } + return false; + } + + /// + /// 按确切的属性名,属性值删除节点 + /// + /// 属性名 + /// 属性值 + /// 是否移除成功 + public bool RemoveNode(string Attribute_name, string Attribute_value) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name] != null) + { + if (item.Attributes[Attribute_name].Value == Attribute_value) + { + root.RemoveChild(item); + xml.Save(path); + return true; + } + } + } + } + return false; + } + + /// + /// 如果节点中有日期属性,把日期之前的节点都删除 + /// + /// 属性名 + /// 截止时间 + /// 是否删除成功 + public bool RemoveNode(string Attribute_name, DateTime dateTime) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < nodeList.Count; i++) + { + if (nodeList[i].Attributes[Attribute_name] != null) + { + DateTime dt = Convert.ToDateTime(nodeList[i].Attributes[Attribute_name].Value); + if (DateTime.Compare(dt, dateTime) < 0) + { + root.RemoveChild(nodeList[i]); + } + } + } + xml.Save(path); + + return true; + } + return false; + } + + /// + /// 判断节点是否存在 + /// + /// 节点名 + /// 返回结果 + public bool NodeExist(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + return true; + } + } + } + return false; + } + + /// + /// 删除所有节点,不包含子节点 + /// + /// 返回删除是否成功 + public bool RemoveAllNode() + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + root.RemoveAll(); + xml.Save(path); + + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs.meta new file mode 100644 index 0000000..160913f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Data/XML/XmlTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69ccb2b689355d94994a1a4d7f031599 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency.meta new file mode 100644 index 0000000..0a8b76e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52cde6d0fdc0e084eacb5678d3ac0192 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute.meta new file mode 100644 index 0000000..be07358 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b3e1133fed8f0f498aa97bcdc8f8635 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs new file mode 100644 index 0000000..86f9f67 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 依赖属性数据验证 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class DataValidationAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs.meta new file mode 100644 index 0000000..76e49c8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c4059f1a0b6bc24ab90bce89de5f97d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs new file mode 100644 index 0000000..a2dc57d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs @@ -0,0 +1,153 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 指定依赖类型。 + /// + [AttributeUsage(AttributeTargets.Class)] + public class DependencyTypeAttribute : Attribute + { + /// + /// 初始化一个依赖类型。当确定某个类型仅以某种特定方式注入时,可以过滤不必要的注入操作,以提高效率。 + /// + /// 可以叠加位域 + public DependencyTypeAttribute(DependencyType type) + { + Type = type; + } + + /// + /// 支持类型。 + /// + public DependencyType Type { get; } + } + + /// + /// 依赖注入类型。 + /// + public enum DependencyType + { + /// + /// 构造函数 + /// + Constructor = 1, + + /// + /// 属性 + /// + Property = 2, + + /// + /// 方法 + /// + Method = 4 + } + + /// + /// 指定依赖类型,构造函数,可用于构造函数,属性,方法。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Property | AttributeTargets.Method)] + public class DependencyInjectAttribute : Attribute + { + /// + /// 初始化一个依赖注入对象。并且指定构造参数。 + /// 当创建时也指定参数时,会覆盖该设定。 + /// + /// + public DependencyInjectAttribute(params object[] ps) + { + Ps = ps; + } + + /// + /// 构造函数 + /// + /// + public DependencyInjectAttribute(bool resolveNullIfNoRegistered) + { + ResolveNullIfNoRegistered = resolveNullIfNoRegistered; + } + + /// + /// 构造参数 + /// + public object[] Ps { get; } + + /// + /// 如果没有注册则返回为空 + /// + public bool ResolveNullIfNoRegistered { get; set; } + } + + /// + /// 参数,属性指定性注入。 + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public class DependencyParamterInjectAttribute : DependencyInjectAttribute + { + /// + /// 参数,属性指定性注入。 + /// + /// + /// + public DependencyParamterInjectAttribute(string key, params object[] ps) : base(ps) + { + Key = key; + } + + /// + /// 类型,参数,属性指定性注入。 + /// + /// + /// + /// + public DependencyParamterInjectAttribute(Type type, string key, params object[] ps) : base(ps) + { + Key = key; + Type = type; + } + + /// + /// 类型,参数,属性指定性注入。 + /// + /// + /// + public DependencyParamterInjectAttribute(Type type, params object[] ps) : base(ps) + { + Key = string.Empty; + Type = type; + } + + /// + /// 注入类型 + /// + public Type Type { get; } + + /// + /// 构造函数 + /// + /// + public DependencyParamterInjectAttribute(bool resolveNullIfNoRegistered) + { + ResolveNullIfNoRegistered = resolveNullIfNoRegistered; + } + + /// + /// 指定键。 + /// + public string Key { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs.meta new file mode 100644 index 0000000..4021ab9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1383630fe17d03e48b469face1c9f038 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs new file mode 100644 index 0000000..063c792 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs @@ -0,0 +1,371 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// IOC容器 + /// + public class Container : IContainer + { + private readonly ConcurrentDictionary m_registrations = new ConcurrentDictionary(); + + /// + /// 初始化一个IOC容器 + /// + public Container() + { + this.RegisterSingleton(this); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + return m_registrations.Values.ToList().GetEnumerator(); + } + + /// + /// + /// + /// + /// + /// + public bool IsRegistered(Type fromType, string key = "") + { + return m_registrations.ContainsKey($"{fromType.FullName}{key}"); + } + + /// + /// + /// + /// + /// + public void Register(DependencyDescriptor descriptor, string key = "") + { + string k = $"{descriptor.FromType.FullName}{key}"; + m_registrations.AddOrUpdate(k, descriptor, (k, v) => { return descriptor; }); + } + + /// + /// + /// + /// + /// + /// + /// + public object Resolve(Type fromType, object[] ps = null, string key = "") + { + if (fromType == typeof(IContainerProvider)) + { + return GetScopedContainer(); + } + string k; + DependencyDescriptor descriptor; + if (fromType.IsGenericType) + { + Type type = fromType.GetGenericTypeDefinition(); + k = $"{type.FullName}{key}"; + if (m_registrations.TryGetValue(k, out descriptor)) + { + if (descriptor.ImplementationFactory != null) + { + return descriptor.ImplementationFactory.Invoke(this); + } + if (descriptor.Lifetime == Lifetime.Singleton) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + lock (descriptor) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + if (descriptor.ToType.IsGenericType) + { + return descriptor.ToInstance = Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps); + } + else + { + return descriptor.ToInstance = Create(descriptor.ToType, ps); + } + } + } + if (descriptor.ToType.IsGenericType) + { + return Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps); + } + else + { + return Create(descriptor.ToType, ps); + } + } + } + k = $"{fromType.FullName}{key}"; + if (m_registrations.TryGetValue(k, out descriptor)) + { + if (descriptor.ImplementationFactory != null) + { + return descriptor.ImplementationFactory.Invoke(this); + } + if (descriptor.Lifetime == Lifetime.Singleton) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + lock (descriptor) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + return descriptor.ToInstance = Create(descriptor.ToType, ps); + } + } + return Create(descriptor.ToType, ps); + } + else if (fromType.IsPrimitive || fromType == typeof(string)) + { + return default; + } + else if (fromType.IsClass && !fromType.IsAbstract) + { + if (fromType.GetCustomAttribute() is DependencyInjectAttribute attribute) + { + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(fromType, key)) + { + return default; + } + } + return Create(fromType, ps); + } + else + { + return default; + } + } + + /// + /// + /// + /// + /// + public void Unregister(DependencyDescriptor descriptor, string key = "") + { + string k = $"{descriptor.FromType.FullName}{key}"; + m_registrations.TryRemove(k, out _); + } + + /// + /// + /// + /// + /// + /// + private object Create(Type toType, object[] ops) + { + ConstructorInfo ctor = toType.GetConstructors().FirstOrDefault(x => x.IsDefined(typeof(DependencyInjectAttribute), true)); + if (ctor is null) + { + //如果没有被特性标记,那就取构造函数参数最多的作为注入目标 + if (toType.GetConstructors().Length == 0) + { + throw new Exception($"没有找到类型{toType.FullName}的公共构造函数。"); + } + ctor = toType.GetConstructors().OrderByDescending(x => x.GetParameters().Length).First(); + } + else + { + if (ops == null) + { + ops = ctor.GetCustomAttribute().Ps; + } + } + + DependencyTypeAttribute dependencyTypeAttribute = null; + if (toType.IsDefined(typeof(DependencyTypeAttribute), true)) + { + dependencyTypeAttribute = toType.GetCustomAttribute(); + } + + var parameters = ctor.GetParameters(); + object[] ps = new object[parameters.Length]; + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Constructor)) + { + for (int i = 0; i < parameters.Length; i++) + { + if (ops != null && ops.Length - 1 >= i) + { + ps[i] = ops[i]; + } + else + { + if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string)) + { + if (parameters[i].HasDefaultValue) + { + ps[i] = parameters[i].DefaultValue; + } + else + { + ps[i] = default; + } + } + else + { + if (parameters[i].IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = parameters[i].GetCustomAttribute(); + Type type = attribute.Type == null ? parameters[i].ParameterType : attribute.Type; + + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + ps[i] = default; + } + else + { + ps[i] = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + ps[i] = Resolve(parameters[i].ParameterType, null); + } + } + } + } + } + object instance = Activator.CreateInstance(toType, ps); + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Property)) + { + var propetys = toType.GetProperties().Where(x => x.IsDefined(typeof(DependencyInjectAttribute), true)); + foreach (var item in propetys) + { + if (item.CanWrite) + { + object obj; + if (item.IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = item.GetCustomAttribute(); + Type type = attribute.Type == null ? item.PropertyType : attribute.Type; + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + obj = null; + } + else + { + obj = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + obj = Resolve(item.PropertyType, null); + } + item.SetValue(instance, obj); + } + } + } + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Method)) + { + var methods = toType.GetMethods( BindingFlags.Default| BindingFlags.Instance| BindingFlags.Static| BindingFlags.Public| BindingFlags.NonPublic).Where(x => x.IsDefined(typeof(DependencyInjectAttribute), true)).ToList(); + foreach (var item in methods) + { + parameters = item.GetParameters(); + ops = item.GetCustomAttribute().Ps; + ps = new object[parameters.Length]; + for (int i = 0; i < ps.Length; i++) + { + if (ops != null && ops.Length - 1 >= i) + { + ps[i] = ops[i]; + } + else + { + if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string)) + { + if (parameters[i].HasDefaultValue) + { + ps[i] = parameters[i].DefaultValue; + } + else + { + ps[i] = default; + } + } + else + { + if (parameters[i].IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = parameters[i].GetCustomAttribute(); + Type type = attribute.Type == null ? parameters[i].ParameterType : attribute.Type; + + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + ps[i] = default; + } + else + { + ps[i] = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + ps[i] = Resolve(parameters[i].ParameterType, null); + } + } + } + } + item.Invoke(instance, ps); + } + } + return instance; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private IContainerProvider GetScopedContainer() + { + Container container = new Container(); + foreach (var item in m_registrations) + { + if (item.Value.Lifetime == Lifetime.Scoped) + { + container.m_registrations.AddOrUpdate(item.Key, new DependencyDescriptor(item.Value.FromType, item.Value.ToType, Lifetime.Singleton), (k, v) => { return v; }); + } + else + { + container.m_registrations.AddOrUpdate(item.Key, item.Value, (k, v) => { return v; }); + } + } + return new ContainerProvider(container); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs.meta new file mode 100644 index 0000000..853caf2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Container.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6ab38bc8550f524cbc0b5057e78ba07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs new file mode 100644 index 0000000..f0bd344 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// IContainerExtensions + /// + public static class ContainerExtension + { + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, TTo instance) + where TFrom : class + where TTo : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), instance); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance) + { + if (instance is null) + { + throw new ArgumentNullException(nameof(instance)); + } + + RegisterSingleton(container, instance.GetType(), instance); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key, TTo instance) + where TFrom : class + where TTo : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), instance, key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, Type fromType, object instance, string key = "") + { + container.Register(new DependencyDescriptor(fromType, instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance, string key = "") + { + container.Register(new DependencyDescriptor(typeof(TFrom), instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance, string key = "") + { + container.Register(new DependencyDescriptor(instance.GetType(), instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key = "") + { + container.Register(new DependencyDescriptor(typeof(TFrom), typeof(TFrom), Lifetime.Singleton), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Singleton), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + #region Transient + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterTransient(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container) + where TFrom : class + { + RegisterTransient(container, typeof(TFrom), typeof(TFrom)); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterTransient(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Transient), key); + return container; + } + + #endregion Transient + + #region Scoped + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterScoped(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container) + where TFrom : class + { + RegisterScoped(container, typeof(TFrom), typeof(TFrom)); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterScoped(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Scoped), key); + return container; + } + + #endregion Scoped + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container, object[] ps, string key = "") + { + return (T)container.Resolve(typeof(T), ps, key); + } + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container) + { + return Resolve(container, null); + } + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container, string key) + { + return Resolve(container, null, key); + } + + #region Unregister + + /// + /// 移除注册信息 + /// + /// + /// + /// + /// + public static IContainer Unregister(this IContainer container, Type fromType, string key = "") + { + container.Unregister(new DependencyDescriptor(fromType), key); + return container; + } + + /// + /// 移除注册信息 + /// + /// + /// + /// + public static IContainer Unregister(this IContainer container, string key = "") + { + container.Unregister(new DependencyDescriptor(typeof(TFrom)), key); + return container; + } + + #endregion Unregister + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs.meta new file mode 100644 index 0000000..5f6c24e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb44fdf72b2f7e841858c8d0bce562e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs new file mode 100644 index 0000000..2f86e97 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + internal class ContainerProvider : IContainerProvider + { + private readonly Container m_container; + + public ContainerProvider(Container container) + { + m_container = container; + } + + public bool IsRegistered(Type fromType, string key = "") + { + return m_container.IsRegistered(fromType, key); + } + + public object Resolve(Type fromType, object[] ps = null, string key = "") + { + return m_container.Resolve(fromType, ps, key); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs.meta new file mode 100644 index 0000000..a752c06 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/ContainerProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9c1c8ca89820554bb1d0286cb70a363 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs new file mode 100644 index 0000000..5ca012e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 注入依赖对象 + /// + public class DependencyDescriptor + { + /// + /// 初始化一个单例实例。 + /// + /// + /// + public DependencyDescriptor(Type fromType, object instance) + { + FromType = fromType; + ToInstance = instance; + Lifetime = Lifetime.Singleton; + ToType = instance.GetType(); + } + + /// + /// 初始化一个完整的服务注册 + /// + /// + /// + /// + public DependencyDescriptor(Type fromType, Type toType, Lifetime lifetime) + { + FromType = fromType; + Lifetime = lifetime; + ToType = toType; + } + + /// + /// 初始化一个简单的的服务描述 + /// + /// + public DependencyDescriptor(Type fromType) + { + FromType = fromType; + } + + /// + /// 实例化工厂委托 + /// + public Func ImplementationFactory { get; set; } + + /// + /// 实例类型 + /// + public Type ToType { get; } + + /// + /// 实例 + /// + public object ToInstance { get; set; } + + /// + /// 生命周期 + /// + public Lifetime Lifetime { get; } + + /// + /// 注册类型 + /// + public Type FromType { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs.meta new file mode 100644 index 0000000..65ecf5e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82d28eb001b403b488fb8229bdaa345d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs new file mode 100644 index 0000000..af93d05 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 依赖对象接口 + /// + public interface IDependencyObject : IDisposable + { + /// + /// 获取依赖注入的值 + /// + /// + /// + /// + public TValue GetValue(IDependencyProperty dp); + + /// + /// 是否有值。 + /// + /// + /// + public bool HasValue(IDependencyProperty dp); + + /// + /// 重置属性值。 + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp); + + /// + /// 设置依赖注入的值 + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value); + } + + /// + /// 依赖项对象. + /// 线程安全。 + /// + public class DependencyObject : DisposableObject, IDependencyObject, System.IDisposable + { + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly ConcurrentDictionary m_dp; + + /// + /// 构造函数 + /// + public DependencyObject() + { + m_dp = new ConcurrentDictionary(); + } + + /// + /// 获取依赖注入的值 + /// + /// + /// + public TValue GetValue(IDependencyProperty dp) + { + if (m_dp.TryGetValue(dp, out object value)) + { + return (TValue)value; + } + else + { + return dp.DefauleValue; + } + } + + /// + /// + /// + /// + /// + public bool HasValue(IDependencyProperty dp) + { + return m_dp.ContainsKey(dp); + } + + /// + /// 移除设定值。 + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp) + { + m_dp.TryRemove(dp, out _); + return this; + } + + /// + /// 设置依赖注入的值 + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value) + { + m_dp.AddOrUpdate(dp, value, (k, v) => v); + return this; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_dp.Clear(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs.meta new file mode 100644 index 0000000..470003d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f2601ee341cf5c4e9b8e8977125aa03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs new file mode 100644 index 0000000..779a801 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// IDependencyProperty + /// + /// + public interface IDependencyProperty + { + /// + /// 默认值 + /// + TValue DefauleValue { get; } + + /// + /// 属性名称 + /// + string Name { get; } + + /// + /// 所属类型 + /// + Type Owner { get; } + } + + /// + /// 依赖项属性 + /// + [DebuggerDisplay("Name={Name},Type={ValueType}")] + public class DependencyProperty : IDependencyProperty + { + /// + /// 属性名称 + /// + protected string m_name; + + /// + /// 所属类型 + /// + protected Type m_owner; + + private TValue m_value; + + /// + /// 依赖项属性 + /// + protected DependencyProperty() + { + } + + /// + /// + /// + public TValue DefauleValue => m_value; + + /// + /// + /// + public string Name => m_name; + + /// + /// + /// + public Type Owner => m_owner; + + /// + /// 注册依赖项属性。 + /// 依赖属性的默认值,可能会应用于所有的 + /// + /// + /// + /// 依赖项属性值,一般该值应该是值类型,因为它可能会被用于多个依赖对象。 + /// + public static DependencyProperty Register(string propertyName, Type owner, TValue value) + { + DependencyProperty dp = new DependencyProperty + { + m_name = propertyName, + m_owner = owner, + m_value = value + }; + return dp; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs.meta new file mode 100644 index 0000000..4919fe8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/DependencyProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e240c80fe75397e47bb2af75096b4f8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs new file mode 100644 index 0000000..ec7d290 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 注入容器接口 + /// + public interface IContainer : IContainerProvider, IEnumerable + { + /// + /// 添加类型描述符。 + /// + /// + /// + void Register(DependencyDescriptor descriptor, string key = ""); + + /// + /// 移除注册信息。 + /// + /// + /// + /// + void Unregister(DependencyDescriptor descriptor, string key = ""); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs.meta new file mode 100644 index 0000000..fcff9d9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c0511a0d14640f46b75303da85b37a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs new file mode 100644 index 0000000..5b8a7e6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 具有区域效应的容器。 + /// + public interface IContainerProvider + { + /// + /// 创建目标类型的对应实例。 + /// + /// + /// + /// + /// + object Resolve(Type fromType, object[] ps = null, string key = ""); + + /// + /// 判断某类型是否已经注册 + /// + /// + /// + /// + bool IsRegistered(Type fromType, string key = ""); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs.meta new file mode 100644 index 0000000..6d582e3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/IContainerProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce5a66ab7a434b346804b3986d3830be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs new file mode 100644 index 0000000..8f7e195 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 注入项的生命周期。 + /// + public enum Lifetime + { + /// + /// 单例对象 + /// + Singleton, + + /// + /// 以接口为区域实例单例。 + /// + Scoped, + + /// + /// 瞬时对象 + /// + Transient + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs.meta new file mode 100644 index 0000000..d9f62fe --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Dependency/Lifetime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3c9241f003c71a4f8f862f4604241e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics.meta new file mode 100644 index 0000000..9a9051b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50cafb445c655b8459f2454fbc69c923 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs new file mode 100644 index 0000000..1dbcf0d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 时间测量器 + /// + public class TimeMeasurer + { + /// + /// 开始运行 + /// + /// + /// + public static TimeSpan Run(Action action) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + action?.Invoke(); + stopwatch.Stop(); + return stopwatch.Elapsed; + } + + /// + /// 异步执行 + /// + /// + /// + public static Task RunAsync(Action action) + { + return EasyTask.Run(() => { return Run(action); }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs.meta new file mode 100644 index 0000000..1d623f4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Diagnostics/TimeMeasurer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 170df2f9965ed9a46b5155b038c6070e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event.meta new file mode 100644 index 0000000..8f66c1f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: beb5b96f0802bf04eaaa3fa778718fea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs new file mode 100644 index 0000000..ed0c076 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// TouchSocketEventArgs + /// + public class TouchSocketEventArgs : EventArgs + { + /// + /// 是否允许操作 + /// + public bool IsPermitOperation { get; set; } + + /// + /// 是否已处理 + /// + public bool Handled { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs.meta new file mode 100644 index 0000000..bd4b04a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Event/TouchSocketEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0467cc1ab2f6f4458366f420f08b44b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions.meta new file mode 100644 index 0000000..9085d06 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3838e0f45a8ce1448b962f9c3c19d87 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs new file mode 100644 index 0000000..7065102 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 未找到消息异常类 + /// + [Serializable] + public class MessageNotFoundException : Exception + { + /// + ///构造函数 + /// + /// + public MessageNotFoundException(string mes) : base(mes) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs.meta new file mode 100644 index 0000000..f858fca --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageNotFoundException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e25db47c7e7a86345b555e7fc254bf83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs new file mode 100644 index 0000000..5619106 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 消息已注册 + /// + [Serializable] + public class MessageRegisteredException : Exception + { + /// + ///构造函数 + /// + /// + public MessageRegisteredException(string mes) : base(mes) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs.meta new file mode 100644 index 0000000..cabb525 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Exceptions/MessageRegisteredException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e44d773fc9eee7e4098052a746610ebb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions.meta new file mode 100644 index 0000000..77cbbf6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9dcd8371bfd854e4fa151ed643aa97ec +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs new file mode 100644 index 0000000..4a3ba10 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// BytesExtension + /// + public static class BytesExtension + { + #region 字节数组扩展 + + /// + /// 转Base64。 + /// + /// + /// + public static string ToBase64(this byte[] data) + { + return Convert.ToBase64String(data); + } + + /// + /// 索引包含数组。 + /// + /// 例如:在{0,1,2,3,1,2,3}中搜索{1,2},则会返回list:[2,5],均为最后索引的位置。 + /// + /// + /// + /// + /// + /// + /// + public static List IndexOfInclude(this byte[] srcByteArray, int offset, int length, byte[] subByteArray) + { + int subByteArrayLen = subByteArray.Length; + List indexes = new List(); + if (length < subByteArrayLen) + { + return indexes; + } + int hitLength = 0; + for (int i = offset; i < length; i++) + { + if (srcByteArray[i] == subByteArray[hitLength]) + { + hitLength++; + } + else + { + hitLength = 0; + } + + if (hitLength == subByteArray.Length) + { + hitLength = 0; + indexes.Add(i); + } + } + + return indexes; + } + + /// + /// 索引第一个包含数组的索引位置,例如:在{0,1,2,3,1,2,3}中索引{2,3},则返回3。 + /// 如果目标数组为null或长度为0,则直接返回offset的值 + /// + /// + /// + /// + /// + /// + public static int IndexOfFirst(this byte[] srcByteArray, int offset, int length, byte[] subByteArray) + { + if (length < subByteArray.Length) + { + return -1; + } + if (subByteArray == null || subByteArray.Length == 0) + { + return offset; + } + int hitLength = 0; + for (int i = offset; i < length + offset; i++) + { + if (srcByteArray[i] == subByteArray[hitLength]) + { + hitLength++; + } + else + { + hitLength = 0; + } + + if (hitLength == subByteArray.Length) + { + return i; + } + } + + return -1; + } + + /// + /// 字节数组转16进制字符 + /// + /// + /// + /// + /// + /// + public static string ByBytesToHexString(this byte[] buffer, int offset, int length, string splite = default) + { + if (string.IsNullOrEmpty(splite)) + { + return BitConverter.ToString(buffer, offset, length).Replace("-", string.Empty); + } + else + { + return BitConverter.ToString(buffer, offset, length).Replace("-", splite); + } + } + + #endregion 字节数组扩展 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs.meta new file mode 100644 index 0000000..cf90ddc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/BytesExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bcaf3e03538434c40bc284032d2bc426 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs new file mode 100644 index 0000000..e680ec9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// DictionaryExtension + /// + public static class DictionaryExtension + { + #region 字典扩展 + + /// + /// 移除满足条件的项目。 + /// + /// + /// + /// + /// + /// + public static int Remove(this ConcurrentDictionary pairs, Func, bool> func) + { + List list = new List(); + foreach (var item in pairs) + { + if (func?.Invoke(item) == true) + { + list.Add(item.Key); + } + } + + int count = 0; + foreach (var item in list) + { + if (pairs.TryRemove(item, out _)) + { + count++; + } + } + return count; + } + +#if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER + + /// + /// 尝试添加 + /// + /// + /// + /// + /// + /// + /// + public static bool TryAdd(this Dictionary dictionary, Tkey tkey, TValue value) + { + if (dictionary.ContainsKey(tkey)) + { + return false; + } + dictionary.Add(tkey, value); + return true; + } + +#endif + + /// + /// 尝试添加 + /// + /// + /// + /// + /// + /// + /// + public static void AddOrUpdate(this Dictionary dictionary, Tkey tkey, TValue value) + { + if (dictionary.ContainsKey(tkey)) + { + dictionary[tkey] = value; + } + else + { + dictionary.Add(tkey, value); + } + } + + /// + /// 获取值。如果键不存在,则返回默认值。 + /// + /// + /// + /// + /// + /// + public static TValue GetValue(this Dictionary dictionary, Tkey tkey) + { + if (dictionary.TryGetValue(tkey, out TValue value)) + { + return value; + } + else + { + return default; + } + } + + #endregion 字典扩展 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs.meta new file mode 100644 index 0000000..3ca6abc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/DictionaryExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f8c42242b7456eb4abd94f060d0847db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs new file mode 100644 index 0000000..e246817 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ +#if NETCOREAPP3_1_OR_GREATER + /// + /// RangeExtension + /// + public static class RangeExtension + { + /// + /// 枚举扩展 + /// + /// + /// + public static CustomIntEnumerator GetEnumerator(this Range range) + { + return new CustomIntEnumerator(range); + } + } + + /// + /// CustomIntEnumerator + /// + public ref struct CustomIntEnumerator + { + private int m_current; + private readonly int m_end; + + /// + /// CustomIntEnumerator + /// + /// + public CustomIntEnumerator(Range range) + { + if (range.End.IsFromEnd) + { + throw new NotSupportedException("不支持无限枚举。"); + } + m_current = range.Start.Value - 1; + m_end = range.End.Value; + } + + /// + /// Current + /// + public int Current => m_current; + + /// + /// MoveNext + /// + /// + public bool MoveNext() + { + m_current++; + return m_current <= m_end; + } + } +#endif +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs.meta new file mode 100644 index 0000000..8bc6ede --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/RangeExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8227077c42c94db48a2ce2f6d6ced401 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs new file mode 100644 index 0000000..4cc3bb4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs @@ -0,0 +1,349 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace TouchSocket.Core +{ + /// + /// StringExtension + /// + public static class StringExtension + { + /// + /// IsNullOrEmpty + /// + /// + /// + public static bool IsNullOrEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + + /// + /// IsNullOrWhiteSpace + /// + /// + /// + public static bool IsNullOrWhiteSpace(this string str) + { + return string.IsNullOrWhiteSpace(str); + } + + /// + /// 当不为null,且不为空。 + /// + /// + /// + public static bool HasValue(this string str) + { + return !string.IsNullOrWhiteSpace(str); + } + + /// + /// 将字符串格式化成指定的数据类型 + /// + /// + /// + /// + /// + /// + public static bool TryParseToType(string str, Type type, out object value, char[] splits = default) + { + if (string.IsNullOrEmpty(str)) + { + value = default; + return true; + } + + if (type == null) + { + value = str; + return true; + } + if (type.IsArray) + { + Type elementType = type.GetElementType(); + string[] strs; + if (splits == null) + { + strs = str.Split(new char[] { ' ', ';', '-', '/' }); + } + else + { + strs = str.Split(splits); + } + + Array array = Array.CreateInstance(elementType, strs.Length); + for (int i = 0, c = strs.Length; i < c; ++i) + { + object o; + if (ConvertSimpleType(strs[i], elementType, out o)) + { + array.SetValue(o, i); + } + else + { + value = default; + return false; + } + } + value = array; + return true; + } + return ConvertSimpleType(str, type, out value); + } + + private static bool ConvertSimpleType(string value, Type destinationType, out object returnValue) + { + if ((value == null) || destinationType.IsInstanceOfType(value)) + { + returnValue = value; + return true; + } + + if (string.IsNullOrEmpty(value)) + { + returnValue = default; + return true; + } + TypeConverter converter = TypeDescriptor.GetConverter(destinationType); + bool flag = converter.CanConvertFrom(value.GetType()); + if (!flag) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!flag && !converter.CanConvertTo(destinationType)) + { + returnValue = default; + return false; + } + try + { + returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType); + } + catch + { + returnValue = default; + return false; + } + return true; + } + + /// + /// 判断字符串compare 在 input字符串中出现的次数 + /// + /// 源字符串 + /// 用于比较的字符串 + /// 字符串compare 在 input字符串中出现的次数 + public static int HitStringCount(this string input, string compare) + { + int index = input.IndexOf(compare); + if (index != -1) + { + return 1 + HitStringCount(input.Substring(index + compare.Length), compare); + } + else + { + return 0; + } + } + + /// + /// 将字符转换为对应的基础类型类型。 + /// + /// + /// 目标类型必须为基础类型 + /// + public static object ParseToType(this string value, Type destinationType) + { + object returnValue; + if ((value == null) || destinationType.IsInstanceOfType(value)) + { + return value; + } + string str = value; + if ((str != null) && (str.Length == 0)) + { + return null; + } + TypeConverter converter = TypeDescriptor.GetConverter(destinationType); + bool flag = converter.CanConvertFrom(value.GetType()); + if (!flag) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!flag && !converter.CanConvertTo(destinationType)) + { + throw new InvalidOperationException("无法转换成类型:" + value.ToString() + "==>" + destinationType); + } + try + { + returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType); + } + catch (Exception e) + { + throw new InvalidOperationException(" 类型转换出错:" + value.ToString() + "==>" + destinationType, e); + } + return returnValue; + } + + /// + /// 只按第一个匹配项分割 + /// + /// + /// + /// + public static string[] SplitFirst(this string str, char split) + { + List s = new List(); + int index = str.IndexOf(split); + if (index > 0) + { + s.Add(str.Substring(0, index).Trim()); + s.Add(str.Substring(index + 1, str.Length - index - 1).Trim()); + } + + return s.ToArray(); + } + + /// + /// 按字符串分割 + /// + /// + /// + /// + public static string[] Split(this string str, string pattern) + { + return Regex.Split(str, pattern); + } + + /// + /// 只按最后一个匹配项分割 + /// + /// + /// + /// + public static string[] SplitLast(this string str, char split) + { + List s = new List(); + int index = str.LastIndexOf(split); + if (index > 0) + { + s.Add(str.Substring(0, index).Trim()); + s.Add(str.Substring(index + 1, str.Length - index - 1).Trim()); + } + + return s.ToArray(); + } + + /// + /// 按格式填充 + /// + /// + /// + /// + public static string Format(this string str, params object[] ps) + { + if (ps == null || ps.Length == 0) + { + return str; + } + try + { + return string.Format(str, ps); + } + catch + { + return str; + } + } + + /// + /// 转换为SHA1。 + /// + /// + /// + /// + public static byte[] ToSha1(this string value, Encoding encoding) + { + using (SHA1 sha1 = SHA1.Create()) + { + return sha1.ComputeHash(encoding.GetBytes(value)); + } + } + + /// + /// 转换为UTF-8数据,效果等于 + /// + /// + /// + public static byte[] ToUTF8Bytes(this string value) + { + return Encoding.UTF8.GetBytes(value); + } + + /// + /// 将16进制的字符转换为数组。 + /// + /// + /// + /// + public static byte[] ByHexStringToBytes(this string hexString, string splite = default) + { + if (!string.IsNullOrEmpty(splite)) + { + hexString = hexString.Replace(splite, string.Empty); + } + + if ((hexString.Length % 2) != 0) + { + hexString += " "; + } + byte[] returnBytes = new byte[hexString.Length / 2]; + for (int i = 0; i < returnBytes.Length; i++) + { + returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + } + return returnBytes; + } + + /// + /// 将16进制的字符转换为int32。 + /// + /// + /// + public static int ByHexStringToInt32(this string hexString) + { + if (string.IsNullOrEmpty(hexString)) + { + return default; + } + return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber); + } + + /// + /// 从Base64转到数组。 + /// + /// + /// + public static byte[] ByBase64ToBytes(this string value) + { + return Convert.FromBase64String(value); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs.meta new file mode 100644 index 0000000..668c658 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/StringExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7af5c1cff95fad741a08c7f3809e274e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs new file mode 100644 index 0000000..89e8a7d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 为System提供扩展。 + /// + public static class SystemExtensions + { + #region 其他 + + /// + /// 安全性释放(不用判断对象是否为空)。不会抛出任何异常。 + /// + /// + /// + public static void SafeDispose(this IDisposable dis) + { + if (dis == default) + { + return; + } + try + { + dis.Dispose(); + } + catch + { + } + } + + #endregion 其他 + + /// + /// 获取自定义attribute + /// + /// + /// + /// + public static T GetAttribute(this Enum enumObj) where T : Attribute + { + Type type = enumObj.GetType(); + Attribute attr = null; + string enumName = Enum.GetName(type, enumObj); //获取对应的枚举名 + FieldInfo field = type.GetField(enumName); + attr = field.GetCustomAttribute(typeof(T), false); + return (T)attr; + } + + /// + /// 格林尼治标准时间 + /// + /// + /// + /// + public static string ToGMTString(this DateTime dt, string v) + { + return dt.ToString("r", CultureInfo.InvariantCulture); + } + +#if !NETCOREAPP3_1_OR_GREATER + + /// + /// 清除所有成员 + /// + /// + /// + public static void Clear(this ConcurrentQueue queue) + { + while (queue.TryDequeue(out _)) + { + } + } + +#endif + + /// + /// 清除所有成员 + /// + /// + /// + /// + public static void Clear(this ConcurrentQueue queue, Action action) + { + while (queue.TryDequeue(out T t)) + { + action?.Invoke(t); + } + } + + /// + /// 获取字节中的指定Bit的值 + /// + /// 字节 + /// Bit的索引值(0-7) + /// + public static int GetBit(this byte @this, short index) + { + byte x; + switch (index) + { + case 0: { x = 0x01; } break; + case 1: { x = 0x02; } break; + case 2: { x = 0x04; } break; + case 3: { x = 0x08; } break; + case 4: { x = 0x10; } break; + case 5: { x = 0x20; } break; + case 6: { x = 0x40; } break; + case 7: { x = 0x80; } break; + default: { return 0; } + } + return (@this & x) == x ? 1 : 0; + } + + /// + /// 设置字节中的指定Bit的值 + /// + /// 字节 + /// Bit的索引值(0-7) + /// Bit值(0,1) + /// + public static byte SetBit(this byte @this, short index, int bitvalue) + { + var _byte = @this; + if (bitvalue == 1) + { + switch (index) + { + case 0: { return _byte |= 0x01; } + case 1: { return _byte |= 0x02; } + case 2: { return _byte |= 0x04; } + case 3: { return _byte |= 0x08; } + case 4: { return _byte |= 0x10; } + case 5: { return _byte |= 0x20; } + case 6: { return _byte |= 0x40; } + case 7: { return _byte |= 0x80; } + default: { return _byte; } + } + } + else + { + switch (index) + { + case 0: { return _byte &= 0xFE; } + case 1: { return _byte &= 0xFD; } + case 2: { return _byte &= 0xFB; } + case 3: { return _byte &= 0xF7; } + case 4: { return _byte &= 0xEF; } + case 5: { return _byte &= 0xDF; } + case 6: { return _byte &= 0xBF; } + case 7: { return _byte &= 0x7F; } + default: { return _byte; } + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs.meta new file mode 100644 index 0000000..63f7349 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd2af935042f61e42b2af22699842380 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs new file mode 100644 index 0000000..a9b65ad --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Net; + +namespace TouchSocket.Core +{ + /// + /// 其他扩展 + /// + public static class SystemNetExtension + { + /// + /// 从中获得IP地址。 + /// + /// + /// + public static string GetIP(this EndPoint endPoint) + { + int r = endPoint.ToString().LastIndexOf(":"); + return endPoint.ToString().Substring(0, r); + } + + /// + /// 从中获得Port。 + /// + /// + /// + public static int GetPort(this EndPoint endPoint) + { + int r = endPoint.ToString().LastIndexOf(":"); + return Convert.ToInt32(endPoint.ToString().Substring(r + 1, endPoint.ToString().Length - (r + 1))); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs.meta new file mode 100644 index 0000000..ad55a6a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/SystemNetExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7807752c3d90e9e49a024fc57de8f753 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs new file mode 100644 index 0000000..225fe3c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// TaskExtension + /// + public static class TaskExtension + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs.meta new file mode 100644 index 0000000..37d2a89 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TaskExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c49b0960f1a70994d9cddbd419221368 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs new file mode 100644 index 0000000..e9fcd72 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 元组扩展 + /// + public static class TupleExtension + { + /// + /// 获取元组的名称列表。 + /// + /// + /// + public static IEnumerable GetTupleElementNames(this ParameterInfo parameter) + { + return ((dynamic)parameter.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")))?.TransformNames; + } + + /// + /// 获取元组的名称列表。 + /// + /// + /// + public static IEnumerable GetTupleElementNames(this MemberInfo memberInfo) + { + return ((dynamic)memberInfo.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")))?.TransformNames; + } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs.meta new file mode 100644 index 0000000..2f08a5c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TupleExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b16c022c69986342bfa7fcb3cec124d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs new file mode 100644 index 0000000..b38d6e7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs @@ -0,0 +1,140 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// TypeExtension + /// + public static class TypeExtension + { + #region Type扩展 + + /// + /// 获取类型 + /// + /// + /// + public static Type GetRefOutType(this Type type) + { + if (type.IsByRef) + { + return type.GetElementType(); + } + else + { + return type; + } + } + + /// + /// 获取默认值 + /// + /// + /// + public static object GetDefault(this Type targetType) + { + return targetType.IsValueType ? Activator.CreateInstance(targetType) : null; + } + + /// + /// 判断是否为静态类。 + /// + /// + /// + public static bool IsStatic(this Type targetType) + { + return targetType.IsAbstract && targetType.IsSealed; + } + + /// + /// 判断为结构体 + /// + /// + /// + public static bool IsStruct(this Type targetType) + { + if (!targetType.IsPrimitive && !targetType.IsClass && !targetType.IsEnum && targetType.IsValueType) + { + return true; + } + return false; + } + + /// + /// 判断该类型是否为可空类型 + /// + /// + /// + public static bool IsNullableType(this Type theType) + { + return (theType.IsGenericType && theType. + GetGenericTypeDefinition().Equals + (TouchSocketCoreUtility.nullableType)); + } + + /// + /// 判断该类型是否为可空类型 + /// + /// + /// + public static bool IsNullableType(this PropertyInfo propertyInfo) + { + var att = propertyInfo.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); + if (att!=null) + { + return true; + } + + return (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType. + GetGenericTypeDefinition().Equals + (TouchSocketCoreUtility.nullableType)); + } + + /// + /// 判断该类型是否为可空类型 + /// + /// + /// + public static bool IsNullableType(this FieldInfo fieldInfo) + { + var att = fieldInfo.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); + if (att != null) + { + return true; + } + + return (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType. + GetGenericTypeDefinition().Equals + (TouchSocketCoreUtility.nullableType)); + } + + /// + /// 判断该类型是否为值元组类型 + /// + /// + /// + public static bool IsValueTuple(this Type theType) + { + return theType.IsValueType && + theType.IsGenericType && + theType.FullName.StartsWith("System.ValueTuple"); + } + + #endregion Type扩展 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs.meta new file mode 100644 index 0000000..dafa80a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Extensions/TypeExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f751645cd47412545a42649c86bb1320 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO.meta new file mode 100644 index 0000000..005b61a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e7d7191ba24df0a4a81587f942116906 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs new file mode 100644 index 0000000..c92dea9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 阻塞式单项读取流。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public abstract partial class BlockReadStream : Stream, IWrite + { + private readonly AutoResetEvent m_inputEvent; + private readonly AutoResetEvent m_readEvent; + private byte[] m_buffer; + private bool m_dis; + private volatile int m_length; + private volatile int m_offset; + + /// + /// 构造函数 + /// + public BlockReadStream() + { + m_readEvent = new AutoResetEvent(false); + m_inputEvent = new AutoResetEvent(false); + ReadTimeout = 5000; + } + + /// + /// + /// + /// + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 还剩余的未读取的长度 + /// + public int CanReadLen + { + get + { + if (m_dis) + { + return 0; + } + return m_length - m_offset; + } + } + + /// + /// 不可使用 + /// + public override bool CanSeek => false; + + /// + /// 不可使用 + /// + public override long Length => throw new NotImplementedException(); + + /// + /// 不可使用 + /// + public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + /// + /// + /// + public override int ReadTimeout { get; set; } + + /// + /// 阻塞读取。 + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) + { + throw new Exception("该流不允许读取。"); + } + int r; + if (m_length > 0) + { + if (m_length > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + m_length -= count; + m_offset += count; + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_length); + r = m_length; + Reset(); + } + } + else + { + //无数据,须等待 + if (m_readEvent.WaitOne(ReadTimeout)) + { + if (m_length == 0) + { + Reset(); + r = 0; + } + else if (m_length > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + m_length -= count; + m_offset += count; + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_length); + r = m_length; + Reset(); + } + } + else + { + throw new TimeoutException(); + } + } + return r; + } + + /// + /// 不可使用 + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + /// + /// 不可使用 + /// + /// + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (m_dis) + { + return; + } + m_dis = true; + Reset(); + m_readEvent.SafeDispose(); + m_inputEvent.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 传输输入. + /// 必须以length为0结束。读取端会超时。 + /// + /// + /// + /// + /// + protected bool Input(byte[] buffer, int offset, int length) + { + m_inputEvent.Reset(); + m_buffer = buffer; + m_offset = offset; + m_length = length; + m_readEvent.Set(); + return m_inputEvent.WaitOne(ReadTimeout); + } + + private void Reset() + { + m_buffer = null; + m_offset = 0; + m_length = 0; + m_readEvent.Reset(); + m_inputEvent.Set(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs.meta new file mode 100644 index 0000000..3967349 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReadStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ded60bc125e142418c381dd11b486b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs new file mode 100644 index 0000000..6f2f4db --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs @@ -0,0 +1,206 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 阻塞式读取。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public abstract partial class BlockReader : DisposableObject + { + private byte[] m_buffer; + private readonly AutoResetEvent m_inputEvent; + private volatile int m_offset; + private readonly AutoResetEvent m_readEvent; + private volatile int m_surLength; + + /// + /// 构造函数 + /// + public BlockReader() + { + m_readEvent = new AutoResetEvent(false); + m_inputEvent = new AutoResetEvent(false); + ReadTimeout = 5000; + } + + /// + /// 可读 + /// + public abstract bool CanRead { get; } + + /// + /// + /// + public int ReadTimeout { get; set; } + + /// + /// 阻塞读取,但不会移动游标。 + /// + /// + /// + /// + /// + public virtual int PeekRead(byte[] buffer, int offset, int count) + { + return PrivateRead(true, buffer, offset, count); + } + + /// + /// 阻塞读取。 + /// + /// + /// + /// + /// + public virtual int Read(byte[] buffer, int offset, int count) + { + return PrivateRead(false, buffer, offset, count); + } + + private int PrivateRead(bool peek, byte[] buffer, int offset, int count) + { + if (!CanRead) + { + throw new Exception("该流不允许读取。"); + } + int r; + if (m_surLength > 0) + { + if (m_surLength > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + if (!peek) + { + m_surLength -= count; + m_offset += count; + } + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_surLength); + r = m_surLength; + if (!peek) + { + Reset(); + } + } + } + else + { + //无数据,须等待 + if (m_readEvent.WaitOne(ReadTimeout)) + { + if (m_surLength == 0) + { + Reset(); + r = 0; + } + else if (m_surLength > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + if (!peek) + { + m_surLength -= count; + m_offset += count; + } + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_surLength); + r = m_surLength; + if (!peek) + { + Reset(); + } + } + } + else + { + throw new TimeoutException(); + } + } + return r; + } + + /// + /// 传输输入. + /// 当以length为0结束。 + /// 否则读取端会超时。 + /// + /// + /// + /// + /// + protected bool Input(byte[] buffer, int offset, int length) + { + //if (this.disposedValue) + //{ + // return false; + //} + m_inputEvent.Reset(); + m_buffer = buffer; + m_offset = offset; + m_surLength = length; + m_readEvent.Set(); + return m_inputEvent.WaitOne(ReadTimeout); + } + + /// + /// 输入完成 + /// + protected bool InputComplate() + { + return Input(new byte[0], 0, 0); + } + + private void Reset() + { + m_buffer = null; + m_offset = 0; + m_surLength = 0; + m_readEvent.Reset(); + m_inputEvent.Set(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + Reset(); + m_readEvent.SafeDispose(); + m_inputEvent.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 析构函数 + /// + ~BlockReader() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs.meta new file mode 100644 index 0000000..3cf5c58 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/BlockReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6914536d9b41474a9f64cb11f025b4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs new file mode 100644 index 0000000..ae77eb0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 控制台行为 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class ConsoleAction + { + private readonly string helpOrder; + + /// + /// 构造函数 + /// + /// 帮助信息指令,如:"h|help|?" + public ConsoleAction(string helpOrder = "h|help|?") + { + this.helpOrder = helpOrder; + + Add(helpOrder, "帮助信息", ShowAll); + + string title = $@" + + _______ _ _____ _ _ + |__ __| | | / ____| | | | | + | | ___ _ _ ___ | |__ | (___ ___ ___ | | __ ___ | |_ + | | / _ \ | | | | / __|| '_ \ \___ \ / _ \ / __|| |/ // _ \| __| + | || (_) || |_| || (__ | | | | ____) || (_) || (__ | <| __/| |_ + |_| \___/ \__,_| \___||_| |_||_____/ \___/ \___||_|\_\\___| \__| + + ------------------------------------------------------------------- + Author : 若汝棋茗 + Version : {System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()} + Gitee : https://gitee.com/rrqm_home + Github : https://github.com/rrqm + API : https://www.yuque.com/rrqm/touchsocket/index + ------------------------------------------------------------------- +"; + Console.WriteLine(title); + } + + /// + /// 显示所有注册指令 + /// + public void ShowAll() + { + int max = actions.Values.Max(a => a.FullOrder.Length) + 8; + + List s = new List(); + foreach (var item in actions) + { + if (!s.Contains(item.Value.FullOrder.ToLower())) + { + s.Add(item.Value.FullOrder.ToLower()); + Console.Write($"[{item.Value.FullOrder}]"); + for (int i = 0; i < max - item.Value.FullOrder.Length; i++) + { + Console.Write("-"); + } + Console.WriteLine(item.Value.Description); + } + } + } + + /// + /// 帮助信息指令 + /// + public string HelpOrder => helpOrder; + + private readonly Dictionary actions = new Dictionary(); + + /// + /// 添加 + /// + /// 指令,多个指令用“|”分割 + /// 描述 + /// + public void Add(string order, string description, Action action) + { + string[] orders = order.ToLower().Split('|'); + foreach (var item in orders) + { + actions.Add(item, new VAction(description, order, action)); + } + } + + /// + /// 执行异常 + /// + public event Action OnException; + + /// + /// 执行,返回值仅表示是否有这个指令,异常获取请使用 + /// + /// + /// + public bool Run(string order) + { + if (actions.TryGetValue(order.ToLower(), out VAction vAction)) + { + try + { + vAction.Action.Invoke(); + } + catch (Exception ex) + { + OnException?.Invoke(ex); + } + return true; + } + else + { + return false; + } + } + } + + internal struct VAction + { + private readonly Action action; + + public Action Action => action; + + private readonly string fullOrder; + + public string FullOrder => fullOrder; + + private readonly string description; + + /// + /// 构造函数 + /// + /// + /// + /// + public VAction(string description, string fullOrder, Action action) + { + this.fullOrder = fullOrder; + this.action = action ?? throw new ArgumentNullException(nameof(action)); + this.description = description ?? throw new ArgumentNullException(nameof(description)); + } + + public string Description => description; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs.meta new file mode 100644 index 0000000..6e96e16 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/ConsoleAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80c8e015bbb366d4e8866f26c0cddc13 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs new file mode 100644 index 0000000..a8e3c88 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// DirectoryUtility + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public static partial class DirectoryUtility + { + /// + /// 复制文件夹及文件 + /// + /// 原文件路径 + /// 目标文件路径 + /// + public static void CopyDirectory(string sourceFolder, string destFolder) + { + //如果目标路径不存在,则创建目标路径 + if (!Directory.Exists(destFolder)) + { + Directory.CreateDirectory(destFolder); + } + //得到原文件根目录下的所有文件 + string[] files = Directory.GetFiles(sourceFolder); + foreach (string file in files) + { + string name = Path.GetFileName(file); + string dest = Path.Combine(destFolder, name); + File.Copy(file, dest);//复制文件 + } + //得到原文件根目录下的所有文件夹 + string[] folders = Directory.GetDirectories(sourceFolder); + foreach (string folder in folders) + { + string name = Path.GetFileName(folder); + string dest = Path.Combine(destFolder, name); + CopyDirectory(folder, dest);//构建目标路径,递归复制文件 + } + } + + /// + /// 获取文件夹下的一级文件夹目录名称,不含子文件夹。 + /// + /// + public static string[] GetDirectories(string sourceFolder) + { + return Directory.GetDirectories(sourceFolder) + .Select(s => Path.GetFileName(s)) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs.meta new file mode 100644 index 0000000..4bce553 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/DirectoryUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95fb622c033a31843a8b0d82c8b1b201 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO.meta new file mode 100644 index 0000000..f9657a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 653e5c4a4818b9446b12c54836a622f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs new file mode 100644 index 0000000..b2d1150 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs @@ -0,0 +1,341 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 文件池。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public static partial class FilePool + { + private static readonly object m_locker = new object(); + + private static readonly ConcurrentDictionary m_pathStorage = new ConcurrentDictionary(); + + private static readonly Timer m_timer; + + static FilePool() + { + m_timer = new Timer(OnTimer, null, 60000, 60000); + } + + /// + /// 获取所有的路径。 + /// + /// + public static string[] GetAllPaths() + { + return m_pathStorage.Keys.ToArray(); + } + + /// + /// 加载文件为读取流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForRead(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + return GetFileStorageForRead(new FileInfo(path)); + } + + /// + /// 加载文件为读取流 + /// + /// + /// + /// + public static FileStorage GetFileStorageForRead(FileInfo fileInfo) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Read) + { + throw new Exception("该路径的文件已经被加载为仅写入模式。"); + } + Interlocked.Increment(ref storage.m_reference); + return storage; + } + lock (m_locker) + { + storage = new FileStorage(fileInfo, FileAccess.Read); + if (m_pathStorage.TryAdd(fileInfo.FullName, storage)) + { + Interlocked.Increment(ref storage.m_reference); + return storage; + } + else + { + return GetFileStorageForRead(fileInfo); + } + + } + } + + /// + /// 加载文件为写流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForWrite(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + return GetFileStorageForWrite(new FileInfo(path)); + } + + /// + /// 加载文件为写流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForWrite(FileInfo fileInfo) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Write) + { + throw new Exception("该路径的文件已经被加载为仅读取模式。"); + } + Interlocked.Increment(ref storage.m_reference); + return storage; + } + lock (m_locker) + { + storage = new FileStorage(fileInfo, FileAccess.Write); + if (m_pathStorage.TryAdd(fileInfo.FullName, storage)) + { + Interlocked.Increment(ref storage.m_reference); + return storage; + } + else + { + return GetFileStorageForWrite(fileInfo); + } + } + } + + /// + /// 获取一个可读可写的Stream对象。 + /// + /// + /// + /// + /// + public static FileStorageStream GetFileStorageStream(string path) + { + return new FileStorageStream(GetFileStorageForWrite(path)); + } + + /// + /// 获取一个可读可写的Stream对象。 + /// + /// + /// + /// + /// + public static FileStorageStream GetFileStorageStream(FileInfo fileInfo) + { + return new FileStorageStream(GetFileStorageForWrite(fileInfo)); + } + + /// + /// 获取一个文件读取访问器 + /// + /// + /// + /// + /// + public static FileStorageReader GetReader(string path) + { + return new FileStorageReader(GetFileStorageForRead(path)); + } + + /// + /// 获取一个文件读取访问器 + /// + /// + /// + /// + /// + public static FileStorageReader GetReader(FileInfo fileInfo) + { + return new FileStorageReader(GetFileStorageForRead(fileInfo)); + } + + /// + /// 获取引用次数。 + /// + /// 必须是全路径。 + /// + /// + /// + public static int GetReferenceCount(string path) + { + if (string.IsNullOrEmpty(path)) + { + return 0; + } + if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) + { + return fileStorage.m_reference; + } + return 0; + } + + /// + /// 获取一个文件写入访问器 + /// + /// 路径 + /// + /// + /// + public static FileStorageWriter GetWriter(string path) + { + return new FileStorageWriter(GetFileStorageForWrite(path)); + } + + /// + /// 获取一个文件写入访问器 + /// + /// + /// + /// + /// + public static FileStorageWriter GetWriter(FileInfo fileInfo) + { + return new FileStorageWriter(GetFileStorageForWrite(fileInfo)); + } + + /// + /// 加载文件为缓存读取流 + /// + /// + /// + /// + /// + public static void LoadFileForCacheRead(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + + path = Path.GetFullPath(path); + if (m_pathStorage.TryGetValue(path, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Read || !storage.Cache) + { + throw new Exception("该路径的文件已经被加载为其他模式。"); + } + return; + } + if (FileStorage.TryCreateCacheFileStorage(path, out FileStorage fileStorage, out string msg)) + { + m_pathStorage.TryAdd(path, fileStorage); + } + else + { + throw new Exception(msg); + } + } + + /// + /// 减少引用次数,并尝试释放流。 + /// + /// + /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 + /// + /// + /// + public static Result TryReleaseFile(string path, int delayTime = 0) + { + if (string.IsNullOrEmpty(path)) + { + return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(path))); + } + path = Path.GetFullPath(path); + if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) + { + if (Interlocked.Decrement(ref fileStorage.m_reference) <= 0) + { + if (delayTime > 0) + { + EasyTask.DelayRun(delayTime, path, (p) => + { + if (GetReferenceCount(p) == 0) + { + if (m_pathStorage.TryRemove((string)p, out fileStorage)) + { + fileStorage.Dispose(); + } + } + }); + return new Result(ResultCode.Success, $"如果在{delayTime}ms后引用仍然为0的话,即被释放。"); + } + else + { + if (m_pathStorage.TryRemove(path, out fileStorage)) + { + fileStorage.Dispose(); + } + return new Result(ResultCode.Success, "流成功释放。"); + } + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.StreamReferencing.GetDescription(path, fileStorage.m_reference)); + } + } + else + { + return new Result(ResultCode.Success, TouchSocketStatus.StreamNotFind.GetDescription(path)); + } + } + + private static void OnTimer(object state) + { + var keys = new List(); + foreach (KeyValuePair item in m_pathStorage) + { + if (DateTime.Now - item.Value.AccessTime > item.Value.AccessTimeout) + { + keys.Add(item.Key); + } + } + foreach (string item in keys) + { + TryReleaseFile(item); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs.meta new file mode 100644 index 0000000..33a3613 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FilePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79959bd11de040b409c124fbd9111357 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs new file mode 100644 index 0000000..7706ae7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs @@ -0,0 +1,229 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 文件存储器。在该存储器中,读写线程安全。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class FileStorage + { + internal volatile int m_reference; + private readonly ReaderWriterLockSlim m_lockSlim; + private bool m_disposedValue; + private byte[] m_fileData; + + /// + /// 初始化一个文件存储器。在该存储器中,读写线程安全。 + /// + internal FileStorage(FileInfo fileInfo, FileAccess fileAccess) : this() + { + this.FileAccess = fileAccess; + this.FileInfo = fileInfo; + this.Path = fileInfo.FullName; + this.m_reference = 0; + this.FileStream = fileAccess == FileAccess.Read ? fileInfo.OpenRead() : fileInfo.OpenWrite(); + this.m_lockSlim = new ReaderWriterLockSlim(); + } + + private FileStorage() + { + this.AccessTime = DateTime.Now; + this.AccessTimeout = TimeSpan.FromSeconds(60); + } + + /// + /// 最后访问时间。 + /// + public DateTime AccessTime { get; private set; } + + /// + /// 访问超时时间。默认10s + /// + public TimeSpan AccessTimeout { get; set; } + + /// + /// 是否为缓存型。为false时,意味着该文件句柄正在被该程序占用。 + /// + public bool Cache { get; private set; } + + /// + /// 访问属性 + /// + public FileAccess FileAccess { get; private set; } + + /// + /// 文件信息 + /// + public FileInfo FileInfo { get; private set; } + + /// + /// 文件流。 + /// 一般情况下,请不要直接访问该对象。否则有可能会产生不可预测的错误。 + /// + public FileStream FileStream { get; private set; } + + /// + /// 文件长度 + /// + public long Length => this.FileStream.Length; + + /// + /// 文件路径 + /// + public string Path { get; private set; } + + /// + /// 引用次数。 + /// + public int Reference => this.m_reference; + + /// + /// 创建一个只读的、已经缓存的文件信息。该操作不会占用文件句柄。 + /// + /// + /// + /// + /// + public static bool TryCreateCacheFileStorage(string path, out FileStorage fileStorage, out string msg) + { + path = System.IO.Path.GetFullPath(path); + if (!File.Exists(path)) + { + fileStorage = null; + msg = TouchSocketStatus.FileNotExists.GetDescription(path); + return false; + } + try + { + fileStorage = new FileStorage() + { + Cache = true, + FileAccess = FileAccess.Read, + FileInfo = new FileInfo(path), + Path = path, + m_reference = 0, + m_fileData = File.ReadAllBytes(path) + }; + msg = null; + return true; + } + catch (Exception ex) + { + fileStorage = null; + msg = ex.Message; + return false; + } + } + + /// + /// 写入时清空缓存区 + /// + public void Flush() + { + this.AccessTime = DateTime.Now; + this.FileStream.Flush(); + } + + /// + /// 从指定位置,读取数据到缓存区。线程安全。 + /// + /// + /// + /// + /// + /// + public int Read(long stratPos, byte[] buffer, int offset, int length) + { + this.AccessTime = DateTime.Now; + using (var writeLock = new WriteLock(this.m_lockSlim)) + { + if (this.m_disposedValue) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + if (this.FileAccess == FileAccess.Write) + { + throw new Exception("该流不允许读取。"); + } + if (this.Cache) + { + int r = (int)Math.Min(this.m_fileData.Length - stratPos, length); + Array.Copy(this.m_fileData, stratPos, buffer, offset, r); + return r; + } + else + { + this.FileStream.Position = stratPos; + return this.FileStream.Read(buffer, offset, length); + } + } + } + + /// + /// 减少引用次数,并尝试释放流。 + /// + /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 + /// + /// + /// + public Result TryReleaseFile(int delayTime = 0) + { + return FilePool.TryReleaseFile(this.Path, delayTime); + } + + /// + /// 从指定位置,写入数据到存储区。线程安全。 + /// + /// + /// + /// + /// + public void Write(long stratPos, byte[] buffer, int offset, int length) + { + this.AccessTime = DateTime.Now; + using (var writeLock = new WriteLock(this.m_lockSlim)) + { + if (this.m_disposedValue) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + if (this.FileAccess == FileAccess.Read) + { + throw new Exception("该流不允许写入。"); + } + this.FileStream.Position = stratPos; + this.FileStream.Write(buffer, offset, length); + } + } + + internal void Dispose() + { + if (this.m_disposedValue) + { + return; + } + using (var writeLock = new WriteLock(this.m_lockSlim)) + { + this.m_disposedValue = true; + this.FileStream.SafeDispose(); + this.m_fileData = null; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs.meta new file mode 100644 index 0000000..4786ec5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef890004fb8251140a56fb3cc5840d35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs new file mode 100644 index 0000000..19badf2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// 文件读取器 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class FileStorageReader : DisposableObject + { + + /// + /// 构造函数 + /// + /// + public FileStorageReader(FileStorage fileStorage) + { + this.FileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// 析构函数 + /// + ~FileStorageReader() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + this.Dispose(disposing: false); + } + + /// + /// 文件存储器 + /// + public FileStorage FileStorage { get; private set; } + + /// + /// 游标位置 + /// + public int Pos + { + get => (int)this.Position; + set => this.Position = value; + } + + /// + /// 游标位置 + /// + public long Position { get; set; } + + /// + /// 读取数据到缓存区 + /// + /// + /// + /// + /// + public int Read(byte[] buffer, int offset, int length) + { + int r = this.FileStorage.Read(this.Position, buffer, offset, length); + this.Position += r; + return r; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.DisposedValue) + { + return; + } + FilePool.TryReleaseFile(this.FileStorage.Path); + this.FileStorage = null; + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs.meta new file mode 100644 index 0000000..c365a04 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d793e0333915e6e49ad09ee90b9e8585 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs new file mode 100644 index 0000000..d870648 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// FileStorageStream。非线程安全。 + /// + //IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class FileStorageStream : Stream + { + private long m_position; + + /// + /// 构造函数 + /// + /// + public FileStorageStream(FileStorage fileStorage) + { + this.FileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// 析构函数 + /// + ~FileStorageStream() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + this.Dispose(disposing: false); + } + + /// + /// + /// + public override bool CanRead => this.FileStorage.FileStream.CanRead; + + /// + /// + /// + public override bool CanSeek => this.FileStorage.FileStream.CanSeek; + + /// + /// + /// + public override bool CanWrite => this.FileStorage.FileStream.CanWrite; + + /// + /// 文件存储器 + /// + public FileStorage FileStorage { get; private set; } + + /// + /// + /// + public override long Length => this.FileStorage.FileStream.Length; + + /// + /// + /// + public override long Position { get => this.m_position; set => this.m_position = value; } + + /// + /// + /// + //[IntelligentCoder.AsyncMethodIgnore] + public override void Flush() + { + this.FileStorage.Flush(); + } + + /// + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + int r = this.FileStorage.Read(this.m_position, buffer, offset, count); + this.m_position += r; + return r; + } + + /// + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + this.m_position = offset; + break; + + case SeekOrigin.Current: + this.m_position += offset; + break; + + case SeekOrigin.End: + this.m_position = this.Length + offset; + break; + } + return this.m_position; + } + + /// + /// + /// + /// + public override void SetLength(long value) + { + this.FileStorage.FileStream.SetLength(value); + } + + /// + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + this.FileStorage.Write(this.m_position, buffer, offset, count); + this.m_position += count; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + FilePool.TryReleaseFile(this.FileStorage.Path); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs.meta new file mode 100644 index 0000000..70058b3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b5865fa49b30704699158d955e5b672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs new file mode 100644 index 0000000..4f270a8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 文件写入器。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class FileStorageWriter : DisposableObject, IWrite + { + + /// + /// 构造函数 + /// + /// + public FileStorageWriter(FileStorage fileStorage) + { + this.FileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// + /// + /// + public virtual void Write(byte[] buffer) + { + this.Write(buffer, 0, buffer.Length); + } + + /// + /// 析构函数 + /// + ~FileStorageWriter() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + this.Dispose(disposing: false); + } + + /// + /// 文件存储器 + /// + public FileStorage FileStorage { get; private set; } + + /// + /// 游标位置 + /// + public int Pos + { + get => (int)this.Position; + set => this.Position = value; + } + + /// + /// 游标位置 + /// + public long Position { get; set; } + + /// + /// 移动Pos到流末尾 + /// + /// + public long SeekToEnd() + { + return this.Position = this.FileStorage.Length; + } + + /// + /// 读取数据到缓存区 + /// + /// + /// + /// + /// + public void Write(byte[] buffer, int offset, int length) + { + this.FileStorage.Write(this.Position, buffer, offset, length); + this.Position += length; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.DisposedValue) + { + return; + } + FilePool.TryReleaseFile(this.FileStorage.Path); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs.meta new file mode 100644 index 0000000..1c57a7a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 345c478f36708794096021225dfa7993 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs new file mode 100644 index 0000000..05488a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs @@ -0,0 +1,313 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace TouchSocket.Core +{ + /// + /// 文件操作 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public static partial class FileUtility + { + /// + /// 获取不重复文件名。 + /// 例如:New.txt已存在时,会返回New(1).txt + /// + /// + /// + public static string GetDuplicateFileName(string fileName) + { + if (!File.Exists(fileName)) + { + return fileName; + } + + int index = 0; + while (true) + { + index++; + string newPath = Path.Combine(Path.GetDirectoryName(fileName), $"{Path.GetFileNameWithoutExtension(fileName)}({index}){Path.GetExtension(fileName)}"); + if (!File.Exists(newPath)) + { + return newPath; + } + } + } + + /// + /// 获取不重复文件夹名称. + /// 例如:NewDir已存在时,会返回NewDir(1) + /// + /// + /// + public static string GetDuplicateDirectoryName(string dirName) + { + if (!Directory.Exists(dirName)) + { + return dirName; + } + + int index = 0; + while (true) + { + index++; + string newPath = Path.Combine(Path.GetDirectoryName(dirName), $"{Path.GetFileNameWithoutExtension(dirName)}({index})"); + if (!System.IO.Directory.Exists(newPath)) + { + return newPath; + } + } + } + + /// + /// 转化为文件大小的字符串,类似10B,10Kb,10Mb,10Gb。 + /// + /// + /// + public static string ToFileLengthString(long length) + { + if (length < 1024) + { + return $"{length}B"; + } + else if (length < 1024 * 1024) + { + return $"{(length / 1024.0).ToString("0.00")}Kb"; + } + else if (length < 1024 * 1024 * 1024) + { + return $"{(length / (1024.0 * 1024)).ToString("0.00")}Mb"; + } + else + { + return $"{(length / (1024.0 * 1024 * 1024)).ToString("0.00")}Gb"; + } + } + + /// + /// 获取文件MD5 + /// + /// + /// + public static string GetFileMD5(string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + return GetStreamMD5(fileStream); + } + } + + /// + /// 获取流MD5 + /// + /// + /// + public static string GetStreamMD5(Stream fileStream) + { + using (HashAlgorithm hash = System.Security.Cryptography.MD5.Create()) + { + return GetStreamHash(fileStream, hash); + } + } + + /// + /// 获得文件Hash值 + /// + /// 文件路径 + /// + public static string GetFileHash256(string filePath) + { + try + { + HashAlgorithm hash = SHA256.Create(); + using (FileStream fileStream = File.OpenRead(filePath)) + { + byte[] HashValue = hash.ComputeHash(fileStream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + } + catch + { + return null; + } + } + + /// + /// 获得流Hash值 + /// + /// + /// + public static string GetStreamHash256(Stream stream) + { + try + { + HashAlgorithm hash = SHA256.Create(); + byte[] HashValue = hash.ComputeHash(stream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + catch + { + return null; + } + } + + /// + /// 获得文件Hash值 + /// + /// 文件路径 + /// + /// + public static string GetFileHash(string filePath, HashAlgorithm hash) + { + try + { + using (FileStream fileStream = File.OpenRead(filePath)) + { + byte[] HashValue = hash.ComputeHash(fileStream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + } + catch + { + return null; + } + } + + /// + /// 获得流Hash值 + /// + /// + /// + /// + public static string GetStreamHash(Stream stream, HashAlgorithm hash) + { + try + { + byte[] HashValue = hash.ComputeHash(stream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + catch + { + return null; + } + } + + /// + /// 获取仅当前文件夹中包含的文件名称,不含全路径。 + /// + /// + /// + public static string[] GetIncludeFileNames(string dirPath) + { + return Directory.GetFiles(dirPath).Select(s => Path.GetFileName(s)).ToArray(); + } + + /// + /// 获取相对路径。 + /// + /// + /// + /// + /// + public static string GetRelativePath(string relativeTo, string path) + { + if (string.IsNullOrEmpty(relativeTo)) throw new ArgumentNullException(nameof(relativeTo)); + if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + + var fromUri = new Uri(relativeTo); + var toUri = new Uri(path); + + if (fromUri.Scheme != toUri.Scheme) + { + // 不是同一种路径,无法转换成相对路径。 + return path; + } + + if (fromUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase) + && !relativeTo.EndsWith("/", StringComparison.OrdinalIgnoreCase) + && !relativeTo.EndsWith("\\", StringComparison.OrdinalIgnoreCase)) + { + // 如果是文件系统,则视来源路径为文件夹。 + fromUri = new Uri(relativeTo + Path.DirectorySeparatorChar); + } + + var relativeUri = fromUri.MakeRelativeUri(toUri); + var relativePath = Uri.UnescapeDataString(relativeUri.ToString()); + + if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)) + { + relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + } + + return relativePath; + } + + /// + /// 删除路径文件 + /// + /// + public static void Delete(string path) + { + if (File.Exists(path)) + { + File.SetAttributes(path, FileAttributes.Normal); + File.Delete(path); + } + } + +# if NET45_OR_GREATER + + [DllImport("kernel32.dll")] + private static extern IntPtr _lopen(string lpPathName, int iReadWrite); + + [DllImport("kernel32.dll")] + private static extern bool CloseHandle(IntPtr hObject); + + private const int OF_READWRITE = 2; + + private const int OF_SHARE_DENY_NONE = 0x40; + + private static readonly IntPtr HFILE_ERROR = new IntPtr(-1); + + /// + /// 判断文件是否被已打开 + /// + /// + /// + public static bool FileIsOpen(string fileFullName) + { + if (!File.Exists(fileFullName)) + { + return false; + } + + IntPtr handle = _lopen(fileFullName, OF_READWRITE | OF_SHARE_DENY_NONE); + + if (handle == HFILE_ERROR) + { + return true; + } + + CloseHandle(handle); + + return false; + } + +#endif + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs.meta new file mode 100644 index 0000000..fab976a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/FileUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bb7d4bf06a058a4c8a431ba300d4760 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs new file mode 100644 index 0000000..bef1eaf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// 包装的流。为避免该流释放时,内部流也会被释放的问题 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public partial class WrapStream : Stream + { + private readonly Stream m_stream; + + /// + /// 包装的流。为避免该流释放时,内部流也会被释放的问题 + /// + /// + public WrapStream(Stream stream) + { + m_stream = stream; + } + + /// + /// + /// + public override bool CanRead => m_stream.CanRead; + + /// + /// + /// + public override bool CanSeek => m_stream.CanSeek; + + /// + /// + /// + public override bool CanWrite => m_stream.CanWrite; + + /// + /// + /// + public override long Length => m_stream.Length; + + /// + /// + /// + public override long Position { get => m_stream.Position; set => m_stream.Position = value; } + + /// + /// + /// + //[IntelligentCoder.AsyncMethodIgnore] + public override void Flush() + { + m_stream.Flush(); + } + + /// + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + return m_stream.Read(buffer, offset, count); + } + + /// + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + return m_stream.Seek(offset, origin); + } + + /// + /// + /// + /// + public override void SetLength(long value) + { + m_stream.SetLength(value); + } + + /// + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + m_stream.Write(buffer, offset, count); + } + + /// + /// 没有关闭效果 + /// + public override void Close() + { + } + + /// + /// 没有释放效果 + /// + /// + protected override void Dispose(bool disposing) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs.meta new file mode 100644 index 0000000..0fedd2f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/IO/WrapStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b328ade10a209046a60fa7fa8ddc39d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger.meta new file mode 100644 index 0000000..a0ae80b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0630a8d6615058648935e18555c739ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs new file mode 100644 index 0000000..a39ff7e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 控制台日志记录器 + /// + public class ConsoleLogger : LoggerBase + { + static ConsoleLogger() + { + Default = new ConsoleLogger(); + } + private readonly ConsoleColor m_consoleBackgroundColor; + + private readonly ConsoleColor m_consoleForegroundColor; + + /// + /// 初始化一个日志记录器 + /// + public ConsoleLogger() + { + m_consoleForegroundColor = Console.ForegroundColor; + m_consoleBackgroundColor = Console.BackgroundColor; + } + + /// + /// 默认的实例 + /// + public static ConsoleLogger Default { get; } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + lock (typeof(ConsoleLogger)) + { + Console.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + Console.Write(" | "); + switch (logType) + { + case LogType.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + + case LogType.Error: + Console.ForegroundColor = ConsoleColor.Red; + break; + + case LogType.Info: + default: + Console.ForegroundColor = m_consoleForegroundColor; + break; + } + Console.Write(logType.ToString()); + Console.ForegroundColor = m_consoleForegroundColor; + Console.Write(" | "); + Console.Write(message); + + if (exception != null) + { + Console.Write(" | "); + Console.Write($"【异常消息】:{exception.Message}"); + Console.Write($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + Console.WriteLine(); + + Console.ForegroundColor = m_consoleForegroundColor; + Console.BackgroundColor = m_consoleBackgroundColor; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs.meta new file mode 100644 index 0000000..8904127 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ConsoleLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bffb2faa3be41554b94c0128967c4c30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs new file mode 100644 index 0000000..7be80a1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 快捷日志 + /// + public class EasyLogger : LoggerBase + { + private readonly Action m_action; + private readonly Action m_action1; + + /// + /// 构造函数 + /// + /// 参数依次为:日志类型,触发源,消息,异常 + public EasyLogger(Action action) + { + m_action = action; + } + + /// + /// 构造函数 + /// + /// 参数为日志消息输出。 + public EasyLogger(Action action) + { + m_action1 = action; + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + try + { + if (m_action != null) + { + m_action.Invoke(logType, source, message, exception); + return; + } + if (m_action1 != null) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + stringBuilder.Append(" | "); + stringBuilder.Append(logType.ToString()); + stringBuilder.Append(" | "); + stringBuilder.Append(message); + + if (exception != null) + { + stringBuilder.Append(" | "); + stringBuilder.Append($"【异常消息】:{exception.Message}"); + stringBuilder.Append($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + stringBuilder.AppendLine(); + m_action1.Invoke(stringBuilder.ToString()); + return; + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs.meta new file mode 100644 index 0000000..a988858 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/EasyLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42a960400e90f5445b2d1e5a96ac0cb1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs new file mode 100644 index 0000000..231aec7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 文件日志记录器 + /// 会在指定目录下,生成logs文件夹,然后按[yyyy-MM-dd].log的形式,每日生成日志 + /// + public class FileLogger : LoggerBase + { + private static string m_rootPath; + + /// + /// 构造函数 + /// + /// 日志根目录 + public FileLogger(string rootPath = null) + { + lock (typeof(FileLogger)) + { + rootPath ??= AppDomain.CurrentDomain.BaseDirectory; + + if (m_rootPath.IsNullOrEmpty()) + { + m_rootPath = Path.Combine(rootPath, "logs"); + } + else if (m_rootPath != Path.Combine(rootPath, "logs")) + { + throw new Exception($"{GetType().Name}无法指向不同的根路径。"); + } + } + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + stringBuilder.Append(" | "); + stringBuilder.Append(logType.ToString()); + stringBuilder.Append(" | "); + stringBuilder.Append(message); + + if (exception != null) + { + stringBuilder.Append(" | "); + stringBuilder.Append($"【异常消息】:{exception.Message}"); + stringBuilder.Append($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + stringBuilder.AppendLine(); + + Print(stringBuilder.ToString()); + } + + private static FileStorageWriter m_writer; + + private void Print(string logString) + { + try + { + lock (typeof(FileLogger)) + { + string dir = Path.Combine(m_rootPath, DateTime.Now.ToString("[yyyy-MM-dd]")); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + if (m_writer == null) + { + int count = 0; + string path = null; + while (true) + { + path = Path.Combine(dir, $"{count:0000}" + ".log"); + if (!File.Exists(path)) + { + m_writer = FilePool.GetWriter(path); + break; + } + count++; + } + } + m_writer.Write(Encoding.UTF8.GetBytes(logString)); + if (m_writer.FileStorage.Length > 1024 * 1024) + { + m_writer.SafeDispose(); + m_writer = null; + } + } + } + catch + { + m_writer.SafeDispose(); + m_writer = null; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs.meta new file mode 100644 index 0000000..086b49f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/FileLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff3ce60e6544fcd4f8d38824128caf9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs new file mode 100644 index 0000000..b7c0886 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// 日志接口 + /// + public interface ILog + { + /// + /// 日志输出类型。 + /// 当的类型,在该设置之内时,才会真正输出日志。 + /// + LogType LogType { get; set; } + + /// + /// 日志记录 + /// + /// + /// + /// + /// + void Log(LogType logType, object source, string message, Exception exception); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs.meta new file mode 100644 index 0000000..9eca1c6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/ILog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8466c1b7ffe50ef40ab706f646294023 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs new file mode 100644 index 0000000..a9d22fc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 日志类型。 + /// + public enum LogType + { + /// + /// 不使用日志类输出 + /// + None = 0, + + /// + /// 更为详细的步骤型日志输出 + /// + Trace = 1, + + /// + /// 调试信息日志 + /// + Debug = 2, + + /// + /// 消息类日志输出 + /// + Info = 4, + + /// + /// 警告类日志输出 + /// + Warning = 8, + + /// + /// 错误类日志输出 + /// + Error = 16, + + /// + /// 不可控中断类日输出 + /// + Critical = 32 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs.meta new file mode 100644 index 0000000..fc4c18b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LogType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba994500529e77e4b9aca519e40e9c8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs new file mode 100644 index 0000000..c23727d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 日志基类 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public abstract partial class LoggerBase : ILog + { + /// + /// 全部的日志类型 + /// + public const LogType All = LogType.None | LogType.Trace | LogType.Debug | LogType.Info | LogType.Warning | LogType.Error | LogType.Critical; + + /// + /// 日志基类 + /// + protected LoggerBase() + { + LogType = All; + } + + /// + /// + /// + public LogType LogType { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public void Log(LogType logType, object source, string message, Exception exception) + { + if (LogType.HasFlag(logType)) + { + WriteLog(logType, source, message, exception); + } + } + + /// + /// 筛选日志后输出 + /// + /// + /// + /// + /// + protected abstract void WriteLog(LogType logType, object source, string message, Exception exception); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs.meta new file mode 100644 index 0000000..be1e284 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76ed5443694a5c746b583e8de2dde674 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs new file mode 100644 index 0000000..4a836d6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// LoggerContainerExtension + /// + public static class LoggerContainerExtension + { + /// + /// 设置日志。 + /// + /// + /// + /// + public static IContainer SetLogger(this IContainer container) + where TLogger : class, ILog + { + container.RegisterTransient(); + return container; + } + + /// + /// 设置单例日志。 + /// + /// + /// + /// + public static IContainer SetSingletonLogger(this IContainer container) where TLogger : class, ILog + { + container.RegisterSingleton(); + return container; + } + + /// + /// 设置实例日志。 + /// + /// + /// + /// + /// + public static IContainer SetSingletonLogger(this IContainer container, TLogger logger) where TLogger : class, ILog + { + container.RegisterSingleton(logger); + return container; + } + + /// + /// 添加控制台日志到日志组。 + /// + /// + /// + public static IContainer AddConsoleLogger(this IContainer container) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new ConsoleLogger()); + return container; + } + + /// + /// 添加委托日志到日志组。 + /// + /// + /// + /// + public static IContainer AddEasyLogger(this IContainer container, Action action) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new EasyLogger(action)); + return container; + } + + /// + /// 添加委托日志到日志组。 + /// + /// + /// + /// + public static IContainer AddEasyLogger(this IContainer container, Action action) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new EasyLogger(action)); + return container; + } + + /// + /// 添加文件日志到日志组。 + /// + /// + /// + /// + public static IContainer AddFileLogger(this IContainer container, string rootPath = null) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new FileLogger(rootPath)); + return container; + } + + /// + /// 添加日志到日志组。 + /// + /// + /// + /// + public static IContainer AddLogger(this IContainer container, ILog logger) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(logger); + return container; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs.meta new file mode 100644 index 0000000..8f3a901 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerContainerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 545d682c304026047ac0b40f5895be93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs new file mode 100644 index 0000000..5b47e5f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs @@ -0,0 +1,274 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// + /// + public static class LoggerExtensions + { + #region LoggerGroup日志 + + /// + /// 指定在中的特定日志类型中输出中断日志 + /// + /// + /// + public static void Critical(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Critical, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出调试日志 + /// + /// + /// + public static void Debug(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Debug, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出错误日志 + /// + /// + /// + public static void Error(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Error, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出错误日志 + /// + /// + /// + /// + public static void Error(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Error, source, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出异常日志 + /// + /// + /// + public static void Exception(this ILog logger, Exception ex) where TLog : ILog + { + logger.Log(LogType.Error, null, ex.Message, ex); + } + + /// + /// 指定在中的特定日志类型中输出异常日志 + /// + /// + /// + /// + public static void Exception(this ILog logger, object source, Exception ex) where TLog : ILog + { + logger.Log(LogType.Error, source, ex.Message, ex); + } + + /// + /// 指定在中的特定日志类型中输出消息日志 + /// + /// + /// + public static void Info(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Info, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出消息日志 + /// + /// + /// + /// + public static void Info(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Info, source, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出日志 + /// + /// + /// + /// + /// + /// + public static void Log(this ILog logger, LogType logType, object source, string message, Exception exception) where TLog : ILog + { + if (logger is LoggerGroup loggerGroup) + { + loggerGroup.Log(logType, source, message, exception); + } + } + + /// + /// 指定在中的特定日志类型中输出详细日志 + /// + /// + /// + public static void Trace(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Trace, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出警示日志 + /// + /// + /// + public static void Warning(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Warning, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出警示日志 + /// + /// + /// + /// + public static void Warning(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Warning, source, msg, null); + } + + #endregion LoggerGroup日志 + + #region 日志 + + /// + /// 输出中断日志 + /// + /// + /// + public static void Critical(this ILog logger, string msg) + { + logger.Log(LogType.Critical, null, msg, null); + } + + /// + /// 输出调试日志 + /// + /// + /// + public static void Debug(this ILog logger, string msg) + { + logger.Log(LogType.Debug, null, msg, null); + } + + /// + /// 输出错误日志 + /// + /// + /// + public static void Error(this ILog logger, string msg) + { + logger.Log(LogType.Error, null, msg, null); + } + + /// + /// 输出错误日志 + /// + /// + /// + /// + public static void Error(this ILog logger, object source, string msg) + { + logger.Log(LogType.Error, source, msg, null); + } + + /// + /// 输出异常日志 + /// + /// + /// + public static void Exception(this ILog logger, Exception ex) + { + logger.Log(LogType.Error, null, ex.Message, ex); + } + + /// + /// 输出异常日志 + /// + /// + /// + /// + public static void Exception(this ILog logger, object source, Exception ex) + { + logger.Log(LogType.Error, source, ex.Message, ex); + } + + /// + /// 输出消息日志 + /// + /// + /// + public static void Info(this ILog logger, string msg) + { + logger.Log(LogType.Info, null, msg, null); + } + + /// + /// 输出消息日志 + /// + /// + /// + /// + public static void Info(this ILog logger, object source, string msg) + { + logger.Log(LogType.Info, source, msg, null); + } + + /// + /// 输出详细日志 + /// + /// + /// + public static void Trace(this ILog logger, string msg) + { + logger.Log(LogType.Trace, null, msg, null); + } + + /// + /// 输出警示日志 + /// + /// + /// + public static void Warning(this ILog logger, string msg) + { + logger.Log(LogType.Warning, null, msg, null); + } + + /// + /// 输出警示日志 + /// + /// + /// + /// + public static void Warning(this ILog logger, object source, string msg) + { + logger.Log(LogType.Warning, source, msg, null); + } + + #endregion 日志 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs.meta new file mode 100644 index 0000000..05f6cd9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2dd64ccc50dfc8943a47993ac46903dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs new file mode 100644 index 0000000..f3745f3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs @@ -0,0 +1,252 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 一组日志记录器 + /// + public class LoggerGroup : LoggerBase + { + private readonly Dictionary m_logs = new Dictionary(); + + /// + /// 一组日志记录器 + /// + /// + public LoggerGroup(params ILog[] logs) + { + if (logs is null) + { + throw new ArgumentNullException(nameof(logs)); + } + foreach (var log in logs) + { + this.AddLogger(log); + } + } + + /// + /// 一组日志记录器 + /// + [DependencyInject] + public LoggerGroup() + { + } + + /// + /// 组内的日志记录器 + /// + public ILog[] Logs => m_logs.Values.ToArray(); + + /// + /// 添加日志组件 + /// + /// + /// + public void AddLogger(string key, ILog logger) + { + m_logs.Add(key, logger); + } + + /// + /// 添加日志组件 + /// + /// + public void AddLogger(ILog logger) + { + m_logs.Add(logger.GetType().FullName, logger); + } + + /// + /// 指定输出中的特定类型的日志 + /// + /// + /// + /// + /// + public void Log(LogType logType, object source, string message, Exception exception) where TLog : ILog + { + try + { + for (int i = 0; i < m_logs.Count; i++) + { + ILog log = Logs[i]; + if (log.GetType() == typeof(TLog)) + { + log.Log(logType, source, message, exception); + } + } + } + catch + { + } + } + + /// + /// 移除日志 + /// + /// + public bool RemoveLogger(ILog logger) + { + return this.RemoveLogger(logger.GetType().FullName); + } + + /// + /// 移除日志 + /// + public bool RemoveLogger(Type loggerType) + { + return this.RemoveLogger(loggerType.FullName); + } + + /// + /// 移除对应键的日志 + /// + /// + /// + public bool RemoveLogger(string key) + { + return m_logs.Remove(key); + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + try + { + for (int i = 0; i < m_logs.Count; i++) + { + Logs[i].Log(logType, source, message, exception); + } + } + catch + { + } + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2) : base(log1, log2) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3) : base(log1, log2, log3) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4) : base(log1, log2, log3, log4) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + where TLog5 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4, TLog5 log5) : base(log1, log2, log3, log4, log5) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + where TLog5 : ILog + where TLog6 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4, TLog5 log5, TLog6 log6) : base(log1, log2, log3, log4, log5, log6) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs.meta new file mode 100644 index 0000000..883fd5f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Logger/LoggerGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3adc94527e95134bbd44fc146bb1299 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper.meta new file mode 100644 index 0000000..4b4864d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 813235368b15a9847a1946aea1381026 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs new file mode 100644 index 0000000..943da9f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs @@ -0,0 +1,189 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 映射数据 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public static partial class Mapper + { + private static readonly ConcurrentDictionary> m_typeToProperty = new ConcurrentDictionary>(); + + /// + /// 简单映射 + /// + /// + /// + /// + /// + public static TTarget Map(this object source, MapperOption option = default) where TTarget : class, new() + { + return (TTarget)Map(source, typeof(TTarget), option); + } + + /// + /// 简单映射 + /// + /// + /// + /// + /// + public static TTarget Map(this TTarget source, MapperOption option = default) where TTarget : class, new() + { + return (TTarget)Map(source, typeof(TTarget), option); + } + + /// + /// 简单映射 + /// + /// + /// + /// + /// + /// + public static TTarget Map(this TSource source, MapperOption option = default) where TTarget : class, new() + { + return (TTarget)Map(source, typeof(TTarget), option); + } + + /// + /// 简单对象映射 + /// + /// + /// + /// + /// + public static object Map(this object source, Type targetType, MapperOption option = default) + { + return Map(source, Activator.CreateInstance(targetType), option); + } + + /// + /// 简单对象映射 + /// + /// + /// + /// + /// + public static object Map(this object source, object target, MapperOption option = default) + { + if (source is null) + { + return default; + } + var sourceType = source.GetType(); + if (sourceType.IsPrimitive || sourceType.IsEnum || sourceType == TouchSocketCoreUtility.stringType) + { + return source; + } + var sourcePairs = m_typeToProperty.GetOrAdd(sourceType, (k) => + { + Dictionary pairs = new Dictionary(); + var ps = k.GetProperties(BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var item in ps) + { + pairs.Add(item.Name, new Property(item)); + } + return pairs; + }); + + var targetPairs = m_typeToProperty.GetOrAdd(target.GetType(), (k) => + { + Dictionary pairs = new Dictionary(); + var ps = k.GetProperties(BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var item in ps) + { + pairs.Add(item.Name, new Property(item)); + } + return pairs; + }); + + foreach (var item in sourcePairs) + { + if (item.Value.CanRead) + { + string pkey = item.Key; + if (option != null && option.MapperProperties != null && option.MapperProperties.ContainsKey(pkey)) + { + pkey = option.MapperProperties[pkey]; + } + + if (option?.IgnoreProperties?.Contains(pkey) == true) + { + continue; + } + if (targetPairs.TryGetValue(pkey, out Property property)) + { + if (property.CanWrite) + { + property.SetValue(target, item.Value.GetValue(source)); + } + } + } + } + return target; + } + + /// + /// 映射List + /// + /// + /// + /// + /// + /// + public static IEnumerable MapList(this IEnumerable list, MapperOption option = default) where T : class where T1 : class, new() + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + List result = new List(); + foreach (var item in list) + { + result.Add(Map(item, option)); + } + return result; + } + + /// + /// 映射List + /// + /// + /// + /// + /// + /// + public static IEnumerable MapList(this IEnumerable list, MapperOption option = default) where T1 : class, new() + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + List result = new List(); + foreach (var item in list) + { + result.Add(Map(item, option)); + } + return result; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs.meta new file mode 100644 index 0000000..4517391 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/Mapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: effd8f7ea76aceb4ea6fa1cf0b38072a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs new file mode 100644 index 0000000..05c595b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 映射配置 + /// + public class MapperOption + { + /// + /// 需要忽略的属性名称 + /// + public List IgnoreProperties { get; set; } + + /// + /// 映射属性名称 + /// + public Dictionary MapperProperties { get; set; } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs.meta new file mode 100644 index 0000000..733f365 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Mapper/MapperOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7778827fc949a8449ad4b3517de061bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_.meta new file mode 100644 index 0000000..cf1743c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2006f75afabb7ea49877c58f08e04c07 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs new file mode 100644 index 0000000..22a9973 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 包接口规范 + /// + public interface IPackage + { + /// + /// 打包。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + void Package(ByteBlock byteBlock); + + /// + /// 解包。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + void Unpackage(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs.meta new file mode 100644 index 0000000..bf4b1a2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/IPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afd13bad495b173498dbe6d00d9fd1eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs new file mode 100644 index 0000000..439f76e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 可承载消息的路由包 + /// + public class MsgRouterPackage : RouterPackage + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + byteBlock.Write(Message); + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + this.Message = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs.meta new file mode 100644 index 0000000..dd08ad7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/MsgRouterPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed85c07cfa9aa114ebf5fa646ccd1b4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs new file mode 100644 index 0000000..9be8fa0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// PackageBase包结构数据。 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public abstract partial class PackageBase : IPackage + { + /// + public abstract void Package(ByteBlock byteBlock); + + /// + public abstract void Unpackage(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs.meta new file mode 100644 index 0000000..87b9877 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad56bf80172849742b136b30dfba420d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs new file mode 100644 index 0000000..7dbe202 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// PackageExtensions + /// + public static class PackageExtensions + { + /// + /// 打包为字节 + /// + /// + /// + public static byte[] PackageAsBytes(this PackageBase packageBase) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + packageBase.Package(byteBlock); + return byteBlock.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs.meta new file mode 100644 index 0000000..306dee1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/PackageExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a34d0794c742a7e4fb929ae61e27c5ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs new file mode 100644 index 0000000..ebfa095 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 具有目标id和源id的路由包 + /// + public class RouterPackage : PackageBase + { + /// + /// 标识是否路由 + /// + public bool Route { get; set; } + + /// + /// 源Id + /// + public string SourceId { get; set; } + + /// + /// 目标Id + /// + public string TargetId { get; set; } + + /// + /// 打包所有的路由包信息。顺序为:先调用,然后 + /// + /// + public override sealed void Package(ByteBlock byteBlock) + { + PackageRouter(byteBlock); + PackageBody(byteBlock); + } + + /// + /// 打包数据体。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void PackageBody(ByteBlock byteBlock) + { + } + + /// + /// 打包路由。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void PackageRouter(ByteBlock byteBlock) + { + byteBlock.Write(Route); + byteBlock.Write(SourceId); + byteBlock.Write(TargetId); + } + + /// + /// 转换目标和源的id。 + /// + public void SwitchId() + { + string value = SourceId; + SourceId = TargetId; + TargetId = value; + } + + /// + public override sealed void Unpackage(ByteBlock byteBlock) + { + UnpackageRouter(byteBlock); + UnpackageBody(byteBlock); + } + + /// + /// 解包数据体。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void UnpackageBody(ByteBlock byteBlock) + { + } + + /// + /// 只解包路由部分。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void UnpackageRouter(ByteBlock byteBlock) + { + Route = byteBlock.ReadBoolean(); + SourceId = byteBlock.ReadString(); + TargetId = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs.meta new file mode 100644 index 0000000..2d6e810 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/RouterPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1292c03c4cd4be34098a49e9b64e971b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs new file mode 100644 index 0000000..0902eed --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// WaitPackage + /// + public class WaitPackage : PackageBase, IWaitResult + { + /// + /// + /// + public string Message { get; set; } + + /// + /// + /// + public long Sign { get; set; } + + /// + /// + /// + public byte Status { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + byteBlock.Write(Sign); + byteBlock.Write(Status); + byteBlock.Write(Message); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + Sign = byteBlock.ReadInt64(); + Status = (byte)byteBlock.ReadByte(); + Message = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs.meta new file mode 100644 index 0000000..bd9300d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad3080c9ef231b04e8d7d9dc4b516f3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs new file mode 100644 index 0000000..d6ee510 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 可等待的路由包。 + /// + public class WaitRouterPackage : MsgRouterPackage, IWaitResult + { + /// + public long Sign { get; set; } + + /// + public byte Status { get; set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Sign); + byteBlock.Write(Status); + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + Sign = byteBlock.ReadInt64(); + Status = (byte)byteBlock.ReadByte(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs.meta new file mode 100644 index 0000000..e713a82 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Packages_/WaitRouterPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91e1c646f8b293544ba8ffd0b0f5e065 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins.meta new file mode 100644 index 0000000..fb77ff7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4042329c42caf014bbe8e722b6f218db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs new file mode 100644 index 0000000..3903ccf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 标识该接口应当还会触发异步接口。 + /// 异步接口方法的返回值应该为Task,且必须以Async结尾。 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class AsyncRaiserAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs.meta new file mode 100644 index 0000000..08c68cb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0ad151db32926d4a80b6450427e1256 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs new file mode 100644 index 0000000..ed9e723 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 插件接口 + /// + public interface IPlugin : IDisposable + { + /// + /// 插件执行顺序 + /// 该属性值越大,越靠前执行。值相等时,按添加先后顺序 + /// 该属性效果,仅在之前设置有效。 + /// + int Order { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs.meta new file mode 100644 index 0000000..0cb095b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a411cb7983edd6247b2b69d898c5d5f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs new file mode 100644 index 0000000..570356b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 具有插件功能的对象 + /// + public interface IPluginObject + { + /// + /// 内置IOC容器 + /// + IContainer Container { get; } + + /// + /// 插件管理器 + /// + IPluginsManager PluginsManager { get; } + + /// + /// 是否已启用插件 + /// + bool UsePlugin { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs.meta new file mode 100644 index 0000000..f26066c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2088d6c3ce618934396b993742d2442d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs new file mode 100644 index 0000000..44ecd18 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 插件管理器接口 + /// + public interface IPluginsManager : IEnumerable + { + /// + /// 标识该插件是否可用。当不可用时,仅可以添加和删除插件,但不会触发插件 + /// + bool Enable { get; set; } + + /// + /// 内置IOC容器 + /// + IContainer Container { get; } + + /// + /// 添加插件 + /// + /// 插件 + /// + void Add(IPlugin plugin); + + /// + /// 移除插件 + /// + /// + void Remove(IPlugin plugin); + + /// + /// 移除插件 + /// + /// + void Remove(Type type); + + /// + /// 清除所有插件 + /// + void Clear(); + + /// + /// 触发对应方法 + /// + /// 接口类型 + /// 触发名称 + /// + /// + bool Raise(string name, object sender, TouchSocketEventArgs e) where TPlugin : IPlugin; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs.meta new file mode 100644 index 0000000..9645d86 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/IPluginsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80ffd58a6c576a246bb233cd4187bfb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs new file mode 100644 index 0000000..80e5fb3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// PlguinObjectExtension + /// + public static class PlguinObjectExtension + { + /// + /// 添加插件 + /// + /// 插件类型 + /// 插件类型实例 + public static TPlugin AddPlugin(this IPluginObject plguinObject) where TPlugin : class, IPlugin + { + plguinObject.Container.RegisterSingleton(); + var obj = plguinObject.Container.Resolve(); + AddPlugin(plguinObject, obj); + return obj; + } + + /// + /// 添加插件 + /// + /// + /// 插件 + /// + public static void AddPlugin(this IPluginObject plguinObject, IPlugin plugin) + { + plguinObject.Container.RegisterSingleton(plugin); + plguinObject.PluginsManager.Add(plugin); + } + + /// + /// 清空插件 + /// + public static void ClearPlugins(this IPluginObject plguinObject) + { + plguinObject.PluginsManager.Clear(); + } + + /// + /// 移除插件 + /// + /// + /// + public static void RemovePlugin(this IPluginObject plguinObject, IPlugin plugin) + { + plguinObject.PluginsManager.Remove(plugin); + } + + /// + /// 移除插件 + /// + /// + /// + public static void RemovePlugin(this IPluginObject plguinObject) where T : IPlugin + { + plguinObject.PluginsManager.Remove(typeof(T)); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs.meta new file mode 100644 index 0000000..98b2a24 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PlguinObjectExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 880cc61139b3600428999258b4070e57 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs new file mode 100644 index 0000000..6a7c8b5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// PluginBase + /// + public class PluginBase : DisposableObject, IPlugin + { + /// + public int Order { get ; set ; } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs.meta new file mode 100644 index 0000000..7b35332 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48020899138b2004984cabe7c0abcced +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs new file mode 100644 index 0000000..abf2394 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 表示插件管理器。 + /// + public class PluginsManager : IPluginsManager + { + private readonly Dictionary> m_pluginInfoes = new Dictionary>(); + private readonly List m_plugins = new List(); + + /// + /// 构造函数 + /// + /// + public PluginsManager(IContainer container) + { + Container = container; + } + + /// + /// + /// + public IContainer Container { get; } + + /// + /// + /// + public bool Enable { get; set; } = true; + + /// + /// 添加插件 + /// + /// 插件 + /// + void IPluginsManager.Add(IPlugin plugin) + { + lock (this) + { + if (plugin == null) + { + throw new ArgumentNullException(); + } + if (plugin.GetType().GetCustomAttribute() is SingletonPluginAttribute singletonPlugin) + { + foreach (var item in m_plugins) + { + if (item.PluginType == plugin.GetType()) + { + throw new InvalidOperationException($"插件{plugin.GetType()}不能重复使用。"); + } + } + } + m_plugins.Add(new PluginModel(plugin, plugin.GetType())); + var types = plugin.GetType().GetInterfaces().Where(a => typeof(IPlugin).IsAssignableFrom(a)).ToArray(); + foreach (var type in types) + { + if (!m_pluginInfoes.ContainsKey(type)) + { + Dictionary pairs = new Dictionary(); + var ms = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + foreach (var item in ms) + { + if (item.GetParameters().Length == 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(item.GetParameters()[1].ParameterType)) + { + if (pairs.ContainsKey(item.Name)) + { + throw new Exception("插件的接口方法不允许重载"); + } + PluginMethod pluginMethod = new PluginMethod(type); + if (item.GetCustomAttribute() != null) + { + var asyncMethod = type.GetMethod($"{item.Name}Async", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + if (asyncMethod == null) + { + throw new Exception("当接口标识为异步时,还应当定义其异步方法,以“Async”结尾"); + } + + if (asyncMethod.GetParameters().Length != 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(asyncMethod.GetParameters()[1].ParameterType)) + { + throw new Exception("异步接口方法不符合设定"); + } + if (asyncMethod.ReturnType != typeof(Task)) + { + throw new Exception("异步接口方法返回值必须为Task。"); + } + pluginMethod.MethodAsync=new Method(asyncMethod); + } + pluginMethod.Method = new Method(item); + pairs.Add(item.Name, pluginMethod); + } + } + m_pluginInfoes.Add(type, pairs); + } + } + + m_plugins.Sort(delegate (PluginModel x, PluginModel y) + { + if (x.Plugin.Order == y.Plugin.Order) return 0; + else if (x.Plugin.Order < y.Plugin.Order) return 1; + else return -1; + }); + + Container.RegisterSingleton(plugin); + } + } + + /// + /// 清除所有插件 + /// + void IPluginsManager.Clear() + { + lock (this) + { + foreach (var item in m_plugins) + { + item.Plugin.SafeDispose(); + } + m_plugins.Clear(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + lock (this) + { + return m_plugins.Select(a => a.Plugin).GetEnumerator(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + lock (this) + { + return m_plugins.Select(a => a.Plugin).GetEnumerator(); + } + } + + /// + /// 触发对应方法 + /// + /// 接口类型,此处也必须是接口类型 + /// 触发名称 + /// + /// + bool IPluginsManager.Raise(string name, object sender, TouchSocketEventArgs e) + { + if (!Enable) + { + return false; + } + if (m_pluginInfoes.TryGetValue(typeof(TPlugin), out var value)) + { + if (value.TryGetValue(name, out PluginMethod pluginMethod)) + { + for (int i = 0; i < m_plugins.Count; i++) + { + if (e.Handled) + { + return true; + } + if (pluginMethod.Type.IsAssignableFrom(m_plugins[i].PluginType)) + { + try + { + pluginMethod.Method.Invoke(m_plugins[i].Plugin, sender, e); + } + catch (Exception ex) + { + Container.Resolve()?.Exception(ex); + } + + try + { + pluginMethod.MethodAsync?.InvokeAsync(m_plugins[i].Plugin, sender, e); + } + catch (Exception ex) + { + Container.Resolve()?.Exception(ex); + } + } + } + } + } + return false; + } + + /// + /// 移除插件 + /// + /// + void IPluginsManager.Remove(IPlugin plugin) + { + lock (this) + { + if (plugin == null) + { + throw new ArgumentNullException(); + } + foreach (var item in m_plugins) + { + if (plugin == item.Plugin) + { + if (m_plugins.Remove(item)) + { + plugin.SafeDispose(); + return; + } + } + } + } + } + + /// + /// 移除插件 + /// + /// + void IPluginsManager.Remove(Type type) + { + lock (this) + { + for (int i = m_plugins.Count - 1; i >= 0; i--) + { + IPlugin plugin = m_plugins[i].Plugin; + if (plugin.GetType() == type) + { + m_plugins.RemoveAt(i); + plugin.SafeDispose(); + } + } + } + } + } + + internal class PluginMethod + { + public PluginMethod(Type type) + { + this.Type = type; + } + public Method Method; + public Method MethodAsync; + public readonly Type Type; + } + + internal class PluginModel + { + public PluginModel(IPlugin plugin, Type pluginType) + { + Plugin = plugin; + PluginType = pluginType; + } + + public IPlugin Plugin; + public Type PluginType; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs.meta new file mode 100644 index 0000000..2f9e0d8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 75c70b2ca4cb4724bb68c42e9d565bf1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs new file mode 100644 index 0000000..074f6d3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// PluginsManagerExtension + /// + public static class PluginsManagerExtension + { + /// + /// 添加插件 + /// + /// 插件类型 + /// 插件类型实例 + public static TPlugin Add(this IPluginsManager pluginsManager) where TPlugin : class, IPlugin + { + pluginsManager.Container.RegisterSingleton(); + var obj = pluginsManager.Container.Resolve(); + pluginsManager.Add(obj); + return obj; + } + + /// + /// 添加插件 + /// + /// 插件类型 + /// + /// 创建插件相关构造函数插件 + /// 插件类型实例 + public static TPlugin Add(this IPluginsManager pluginsManager, params object[] ps) where TPlugin : class, IPlugin + { + pluginsManager.Container.RegisterSingleton(); + var obj = pluginsManager.Container.Resolve(ps); + pluginsManager.Add(obj); + return obj; + } + + /// + /// 清空插件 + /// + public static void Clear(this IPluginsManager pluginsManager) + { + pluginsManager.Clear(); + } + + /// + /// 移除插件 + /// + /// + /// + public static void Remove(this IPluginsManager pluginsManager, IPlugin plugin) + { + pluginsManager.Remove(plugin); + } + + /// + /// 移除插件 + /// + /// + /// + public static void Remove(this IPluginsManager pluginsManager) where T : IPlugin + { + pluginsManager.Remove(typeof(T)); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs.meta new file mode 100644 index 0000000..d7db6b4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/PluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b22d96771955ffc49825a228131b3392 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs new file mode 100644 index 0000000..9353168 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 标识插件只能注册一次。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] + public sealed class SingletonPluginAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs.meta new file mode 100644 index 0000000..d75a312 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c59c8a2c28cf9364685f7e5ac2beea25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool.meta new file mode 100644 index 0000000..9abbff0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cdb873626f989c64da1f211c6ffab8c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool.meta new file mode 100644 index 0000000..378f201 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c654a0ea165eaad43839b89ee02d3c6d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs new file mode 100644 index 0000000..5b5a59c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 对象池接口 + /// + public interface IObjectPool : IDisposable + { + /// + /// 可使用数量 + /// + int FreeSize { get; } + + /// + /// 清空池中对象 + /// + void Clear(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs.meta new file mode 100644 index 0000000..e6f7de0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1023f7a181bcefa4b91a2f4a809bd944 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs new file mode 100644 index 0000000..8a8ef01 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 对象池单位接口 + /// + public interface IPoolObject + { + /// + /// 是否为新建对象 + /// + bool NewCreate { get; set; } + + /// + /// 初创建对象 + /// + void Create(); + + /// + /// 重新创建对象 + /// + void Recreate(); + + /// + /// 销毁对象 + /// + void Destroy(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs.meta new file mode 100644 index 0000000..ece74e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ee2e26e2a8d0ec4595236155b2f282b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs new file mode 100644 index 0000000..9861f84 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 对象池 + /// + /// + public class ObjectPool : IObjectPool where T : IPoolObject + { + private readonly ConcurrentQueue m_queue = new ConcurrentQueue(); + + private bool m_autoCreate = true; + + private int m_freeSize; + + /// + /// 构造函数 + /// + /// + public ObjectPool(int capacity) + { + Capacity = capacity; + } + + /// + /// 构造函数 + /// + public ObjectPool() + { + } + + /// + /// 是否自动生成 + /// + public bool AutoCreate + { + get => m_autoCreate; + set => m_autoCreate = value; + } + + /// + /// 对象池容量 + /// + public int Capacity { get; set; } + + /// + /// 可使用(创建)数量 + /// + public int FreeSize => m_freeSize; + + /// + /// 清除池中所有对象 + /// + public void Clear() + { + while (m_queue.TryDequeue(out _)) + { + } + } + + /// + /// 注销对象 + /// + /// + public void DestroyObject(T t) + { + t.Destroy(); + if (m_freeSize < Capacity) + { + Interlocked.Increment(ref m_freeSize); + m_queue.Enqueue(t); + } + } + + /// + /// 释放对象 + /// + public void Dispose() + { + Clear(); + } + + /// + /// 获取所有对象 + /// + /// + public T[] GetAllObject() + { + List ts = new List(); + while (m_queue.TryDequeue(out T t)) + { + ts.Add(t); + } + return ts.ToArray(); + } + + /// + /// 获取对象T + /// + /// + public T GetObject() + { + if (m_queue.TryDequeue(out T t)) + { + t.Recreate(); + t.NewCreate = false; + Interlocked.Decrement(ref m_freeSize); + return t; + } + if (m_autoCreate) + { + t = (T)Activator.CreateInstance(typeof(T)); + t.Create(); + t.NewCreate = true; + } + return t; + } + + /// + /// 预获取 + /// + /// + public T PreviewGetObject() + { + m_queue.TryPeek(out T t); + return t; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs.meta new file mode 100644 index 0000000..8546f38 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09bbe72a229ac014c80c499e8511205e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection.meta new file mode 100644 index 0000000..8d03031 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c1852001d492a847844c400a8c663b7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs new file mode 100644 index 0000000..b03cd22 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// DynamicMethodMemberAccessor + /// + public class DynamicMethodMemberAccessor : IMemberAccessor + { + private static ConcurrentDictionary classAccessors = new ConcurrentDictionary(); + + /// + /// 获取属性 + /// + public Func OnGetProperties { get; set; } + + /// + /// 获取字段 + /// + public Func OnGetFieldInfes { get; set; } + + /// + public object GetValue(object instance, string memberName) + { + return FindClassAccessor(instance).GetValue(instance, memberName); + } + + /// + public void SetValue(object instance, string memberName, object newValue) + { + FindClassAccessor(instance).SetValue(instance, memberName, newValue); + } + + private IMemberAccessor FindClassAccessor(object instance) + { + var typekey = instance.GetType(); + if (!classAccessors.TryGetValue(typekey, out IMemberAccessor classAccessor)) + { + MemberAccessor memberAccessor = new MemberAccessor(instance.GetType()); + if (this.OnGetFieldInfes != null) + { + memberAccessor.OnGetFieldInfes = this.OnGetFieldInfes; + } + + if (this.OnGetProperties != null) + { + memberAccessor.OnGetProperties = this.OnGetProperties; + } + memberAccessor.Build(); + classAccessor = memberAccessor; + classAccessors.TryAdd(typekey, classAccessor); + } + return classAccessor; + } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs.meta new file mode 100644 index 0000000..12a8756 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0f88d1391193fd4391e220c50ede926 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs new file mode 100644 index 0000000..ae93834 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace TouchSocket.Core +{ + /// + /// 表达式复制 + /// + public class ExpressionMapper + { + private static readonly Dictionary m_dic = new Dictionary(); + + /// + /// 字典缓存表达式树 + /// + public static TOut Trans(TIn tIn) + { + string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName); + if (!m_dic.ContainsKey(key)) + { + ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p"); + List memberBindingList = new List(); + foreach (var item in typeof(TOut).GetProperties()) + { + MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name)); + MemberBinding memberBinding = Expression.Bind(item, property); + memberBindingList.Add(memberBinding); + } + foreach (var item in typeof(TOut).GetFields()) + { + MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name)); + MemberBinding memberBinding = Expression.Bind(item, property); + memberBindingList.Add(memberBinding); + } + MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); + Expression> lambda = Expression.Lambda>(memberInitExpression, parameterExpression); + Func func = lambda.Compile();//拼装是一次性的 + m_dic[key] = func; + } + return ((Func)m_dic[key]).Invoke(tIn); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs.meta new file mode 100644 index 0000000..bb74ab2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/ExpressionMapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aee368c3f534ce5478873a2efa0e6fb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs new file mode 100644 index 0000000..a1738da --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 一个成员访问接口 + /// + public interface IMemberAccessor + { + /// + /// 获取指定成员的值 + /// + /// + /// + /// + object GetValue(object instance, string memberName); + + /// + ///设置指定成员的值 + /// + /// + /// + /// + void SetValue(object instance, string memberName, object newValue); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs.meta new file mode 100644 index 0000000..fe732fd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/IMemberAccessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 456e1b958d3e6764bb98fa5ce9533648 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs new file mode 100644 index 0000000..d08aba8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 用于表达式树的成员 + /// + public abstract class Member + { + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs.meta new file mode 100644 index 0000000..ab2934b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Member.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb8f6fb09577c90438c296ee42050174 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs new file mode 100644 index 0000000..deb4513 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 动态成员访问器 + /// + /// + public class MemberAccessor : MemberAccessor + { + /// + /// 动态成员访问器 + /// + public MemberAccessor() : base(typeof(T)) + { + + } + } + + /// + /// 动态成员访问器 + /// + public class MemberAccessor : IMemberAccessor + { + Func GetValueDelegate; + + Action SetValueDelegate; + + /// + /// 动态成员访问器 + /// + /// + public MemberAccessor(Type type) + { + Type = type; + this.OnGetFieldInfes = (t) => { return t.GetFields(); }; + this.OnGetProperties = (t) => { return t.GetProperties(); }; + } + + private Dictionary dicFieldInfes; + private Dictionary dicProperties; + /// + /// 构建 + /// + public void Build() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + dicFieldInfes = this.OnGetFieldInfes.Invoke(Type).ToDictionary(a => a.Name); + dicProperties = this.OnGetProperties.Invoke(Type).ToDictionary(a => a.Name); + } + + GetValueDelegate = GenerateGetValue(); + SetValueDelegate = GenerateSetValue(); + } + + /// + /// 获取属性 + /// + public Func OnGetProperties { get; set; } + + /// + /// 获取字段 + /// + public Func OnGetFieldInfes { get; set; } + + /// + /// 所属类型 + /// + public Type Type { get; } + + /// + public object GetValue(object instance, string memberName) + { + return GetValueDelegate(instance, memberName); + } + + /// + public void SetValue(object instance, string memberName, object newValue) + { + SetValueDelegate(instance, memberName, newValue); + } + + private Func GenerateGetValue() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + return (obj, key) => + { + if (dicFieldInfes.TryGetValue(key, out var value1)) + { + return value1.GetValue(obj); + } + if (dicProperties.TryGetValue(key, out var value2)) + { + return value2.GetValue(obj); + } + return default; + }; + } + + var instance = Expression.Parameter(typeof(object), "instance"); + var memberName = Expression.Parameter(typeof(string), "memberName"); + var nameHash = Expression.Variable(typeof(int), "nameHash"); + var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); + var cases = new List(); + foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) + { + var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); + } + foreach (var propertyInfo in this.OnGetProperties.Invoke(Type)) + { + var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); + } + if (cases.Count == 0) + { + return (a, b) => default; + } + var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); + var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); + + return Expression.Lambda>(methodBody, instance, memberName).Compile(); + } + + private Action GenerateSetValue() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + return (obj, key, value) => + { + if (dicFieldInfes.TryGetValue(key, out var value1)) + { + value1.SetValue(obj, value); + } + if (dicProperties.TryGetValue(key, out var value2)) + { + value2.SetValue(obj, value); + } + }; + } + + var instance = Expression.Parameter(typeof(object), "instance"); + var memberName = Expression.Parameter(typeof(string), "memberName"); + var newValue = Expression.Parameter(typeof(object), "newValue"); + var nameHash = Expression.Variable(typeof(int), "nameHash"); + var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); + var cases = new List(); + foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) + { + var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); + var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.FieldType)); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); + } + foreach (var propertyInfo in this.OnGetProperties(Type)) + { + if (!propertyInfo.CanWrite) + { + continue; + } + var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); + var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.PropertyType)); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); + } + if (cases.Count == 0) + { + return (a, b, c) => { }; + } + var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); + var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); + + return Expression.Lambda>(methodBody, instance, memberName, newValue).Compile(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs.meta new file mode 100644 index 0000000..6a2f43a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberAccessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2e7e69d8f6839a428c3774d7f5af27b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs new file mode 100644 index 0000000..e1321d1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性的Getter + /// + public class MemberGetter + { + /// + /// get方法委托 + /// + private readonly Func m_getFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberGetter(PropertyInfo property) + { + m_getFunc = CreateGetterDelegate(property); + } + + /// + /// 表示类型字段或属性的Getter + /// + /// + public MemberGetter(FieldInfo fieldInfo) + { + m_getFunc = CreateGetterDelegate(fieldInfo); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + public object Invoke(object instance) + { + return m_getFunc.Invoke(instance); + } + + private static Func CreateGetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_property = Expression.Property(body_instance, property); + var body_return = Expression.Convert(body_property, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + + private static Func CreateGetterDelegate(FieldInfo fieldInfo) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, fieldInfo.DeclaringType); + var body_field = Expression.Field(body_instance, fieldInfo); + var body_return = Expression.Convert(body_field, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs.meta new file mode 100644 index 0000000..94447ba --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberGetter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ff2c5961bd09814ebeae792a034c553 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs new file mode 100644 index 0000000..8dc8faf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性的设置器 + /// + public class MemberSetter + { + /// + /// set方法委托 + /// + private readonly Action setFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberSetter(PropertyInfo property) + { + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + setFunc = CreateSetterDelegate(property); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void Invoke(object instance, object value) + { + setFunc.Invoke(instance, value); + } + + private static Action CreateSetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var param_value = Expression.Parameter(typeof(object)); + + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_value = Expression.Convert(param_value, property.PropertyType); + var body_call = Expression.Call(body_instance, property.GetSetMethod(true), body_value); + + return Expression.Lambda>(body_call, param_instance, param_value).Compile(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs.meta new file mode 100644 index 0000000..6e2727c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/MemberSetter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e42a8c9c9c30eb4587e585461fb63d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs new file mode 100644 index 0000000..2514240 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// Task类型 + /// + public enum TaskReturnType + { + /// + /// 没有Task + /// + None, + + /// + /// 仅返回Task + /// + Task, + + /// + /// 返回Task的值 + /// + TaskObject + } + + /// + /// 表示方法 + /// + public class Method + { + private readonly MethodInfo m_info; + + /// + /// 方法执行委托 + /// + private readonly Func m_invoker; + + private readonly bool m_isByRef; + + /// + /// 方法 + /// + /// 方法信息 + public Method(MethodInfo method) + { + m_info = method ?? throw new ArgumentNullException(nameof(method)); + Name = method.Name; + Static = method.IsStatic; + foreach (var item in method.GetParameters()) + { + if (item.ParameterType.IsByRef) + { + m_isByRef = true; + } + } + if (this.m_isByRef||GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + if (method.ReturnType == typeof(Task)) + { + HasReturn = false; + TaskType = TaskReturnType.Task; + } + else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + HasReturn = true; + ReturnType = method.ReturnType.GetGenericArguments()[0]; + TaskType = TaskReturnType.TaskObject; + } + else if (method.ReturnType == typeof(void)) + { + HasReturn = false; + TaskType = TaskReturnType.None; + } + else + { + HasReturn = true; + TaskType = TaskReturnType.None; + ReturnType = method.ReturnType; + } + } + else + { + m_invoker = CreateInvoker(method); + } + } + + /// + /// 是否具有返回值 + /// + public bool HasReturn { get; private set; } + + /// + /// 方法信息 + /// + public MethodInfo Info => m_info; + + /// + /// 是否有引用类型 + /// + public bool IsByRef => m_isByRef; + + /// + /// 获取方法名 + /// + public string Name { get; protected set; } + + /// + /// 返回值类型。 + /// 当方法为void或task时,为null + /// 当方法为task泛型时,为泛型元素类型 + /// + public Type ReturnType { get; private set; } + + /// + /// 是否为静态函数 + /// + public bool Static { get; private set; } + + /// + /// 返回值的Task类型。 + /// + public TaskReturnType TaskType { get; private set; } + + /// + /// 执行方法。 + /// 当方法为void或task时,会返回null + /// 当方法为task泛型时,会wait后的值 + /// 注意:当调用方为UI主线程时,调用异步方法,则极有可能发生死锁。 + /// + /// 实例 + /// 参数 + /// + public object Invoke(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return re; + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + task.Wait(); + return default; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + task.Wait(); + return task.GetType().GetProperty("Result").GetValue(task); + } + default: + return default; + } + } + + /// + /// 异步调用 + /// + /// + /// + /// + public Task InvokeAsync(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + throw new Exception("该方法不包含Task。"); + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return (Task)re; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return (Task)re; + } + default: + return default; + } + } + + /// + /// 调用异步结果 + /// + /// + /// + /// + public async Task InvokeObjectAsync(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return re; + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + await task; + return default; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + await task; + return task.GetType().GetProperty("Result").GetValue(task); + } + default: + return default; + } + } + + /// + /// 生成方法的调用委托 + /// + /// 方法成员信息 + /// + /// + private Func CreateInvoker(MethodInfo method) + { + var instance = Expression.Parameter(typeof(object), "instance"); + var parameters = Expression.Parameter(typeof(object[]), "parameters"); + + var instanceCast = method.IsStatic ? null : Expression.Convert(instance, method.DeclaringType); + var parametersCast = method.GetParameters().Select((p, i) => + { + var parameter = Expression.ArrayIndex(parameters, Expression.Constant(i)); + return Expression.Convert(parameter, p.ParameterType); + }); + + var body = Expression.Call(instanceCast, method, parametersCast); + + if (method.ReturnType == typeof(Task)) + { + HasReturn = false; + TaskType = TaskReturnType.Task; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + TaskType = TaskReturnType.TaskObject; + HasReturn = true; + ReturnType = method.ReturnType.GetGenericArguments()[0]; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + else if (method.ReturnType == typeof(void)) + { + HasReturn = false; + TaskType = TaskReturnType.None; + var action = Expression.Lambda>(body, instance, parameters).Compile(); + return (_instance, _parameters) => + { + action.Invoke(_instance, _parameters); + return null; + }; + } + else + { + HasReturn = true; + TaskType = TaskReturnType.None; + ReturnType = method.ReturnType; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs.meta new file mode 100644 index 0000000..5e8b259 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Method.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a0dcc17f31a45545b8ff5389293d99d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs new file mode 100644 index 0000000..2ee7133 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性 + /// + public class Property: Member + { + /// + /// 类型属性的Setter缓存 + /// + private static readonly ConcurrentDictionary m_cached = new ConcurrentDictionary(); + + /// + /// 获取器 + /// + private readonly MemberGetter m_geter; + + /// + /// 设置器 + /// + private readonly MemberSetter m_seter; + + /// + /// 属性 + /// + /// 属性信息 + public Property(PropertyInfo property) + { + Name = property.Name; + Info = property; + + if (property.CanRead == true) + { + CanRead = true; + m_geter = new MemberGetter(property); + } + if (property.CanWrite == true) + { + CanWrite = true; + m_seter = new MemberSetter(property); + } + } + + /// + /// 是否可以读取 + /// + public bool CanRead { get; private set; } + + /// + /// 是否可以写入 + /// + public bool CanWrite { get; private set; } + + /// + /// 获取属性信息 + /// + public PropertyInfo Info { get; private set; } + + /// + /// 获取属性名称 + /// + public string Name { get; protected set; } + + /// + /// 从类型的属性获取属性 + /// + /// 类型 + /// + public static Property[] GetProperties(Type type) + { + return m_cached.GetOrAdd(type, t => t.GetProperties().Select(p => new Property(p)).ToArray()); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + /// + public object GetValue(object instance) + { + if (m_geter == null) + { + throw new NotSupportedException(); + } + return m_geter.Invoke(instance); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void SetValue(object instance, object value) + { + if (m_seter == null) + { + throw new NotSupportedException($"{Name}不允许赋值"); + } + m_seter.Invoke(instance, value); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs.meta new file mode 100644 index 0000000..cd03e95 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Reflection/Property.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03d3aeeb4e2df9d4f894c7592f45e729 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run.meta new file mode 100644 index 0000000..4dcf4ad --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0f08273be6d15d40859feb70a83f955 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action.meta new file mode 100644 index 0000000..a9e6dfb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d72a1569463f411418e370d0abc6ad50 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs new file mode 100644 index 0000000..822d9d6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 易用组件 + /// + public class EasyTask + { + static EasyTask() + { + InitCompletedTask(); + } + + private static readonly ConcurrentDictionary timers = new ConcurrentDictionary(); + +#if DEBUG + + /// + /// Timers + /// + public static ConcurrentDictionary Timers => timers; + +#endif + + /// + /// 延迟执行 + /// + /// + /// + public static void DelayRun(TimeSpan delayTimeSpan, Action action) + { + DelayRun(delayTimeSpan.Milliseconds, action); + } + + /// + /// 延迟执行 + /// + /// + /// + /// + public static void DelayRun(TimeSpan delayTimeSpan, T status, Action action) + { + DelayRun(delayTimeSpan.Milliseconds, status, action); + } + + /// + /// 延迟执行 + /// + /// + /// + public static void DelayRun(int delay, Action action) + { + object obj = new object(); + Timer timer = new Timer((o) => + { + if (timers.TryRemove(o, out Timer timer1)) + { + timer1.Dispose(); + } + action?.Invoke(); + }, obj, delay, Timeout.Infinite); + timers.TryAdd(obj, timer); + } + + /// + /// 延迟执行 + /// + /// + /// + /// + public static void DelayRun(int delay, T status, Action action) + { + object obj = new object(); + Timer timer = new Timer((o) => + { + if (timers.TryRemove(o, out Timer timer1)) + { + timer1.Dispose(); + } + action?.Invoke(status); + }, obj, delay, Timeout.Infinite); + timers.TryAdd(obj, timer); + } + + /// + /// Task异步 + /// + /// + /// + public static Task Run(T statu, Action action) + { + return Task.Factory.StartNew(() => + { + action.Invoke(statu); + }); + } + + /// + /// Task异步 + /// + /// + /// + /// + public static Task Run(Func function) + { + return Task.Factory.StartNew(function); + } + + /// + /// Task异步 + /// + /// + /// + public static Task Run(Action action) + { + return Task.Factory.StartNew(action); + } + + /// + /// 已完成的Task + /// + public static Task CompletedTask { get; private set; } + + private static void InitCompletedTask() + { +#if NET45_OR_GREATER + Task task = new Task(() => { }); + task.Start(); + task.Wait(); + CompletedTask = task; +#else + CompletedTask = Task.CompletedTask; +#endif + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs.meta new file mode 100644 index 0000000..552aae4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/EasyTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b360c2fc7dc98b40a5bfeb5c7055c17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs new file mode 100644 index 0000000..8bda09c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 循环动作 + /// + public class LoopAction : EasyTask, IDisposable + { + /// + /// 析构函数 + /// + ~LoopAction() + { + Dispose(); + } + + private int executedCount; + + private readonly TimeSpan m_interval; + + private readonly int m_loopCount; + + private readonly EventWaitHandle m_waitHandle; + + private LoopAction(int count, TimeSpan interval, Action action) + { + m_loopCount = count; + this.action = action; + m_interval = interval; + m_waitHandle = new AutoResetEvent(false); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 每次循环间隔 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, TimeSpan interval, Action action) + { + return new LoopAction(count, interval, action); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 每次循环间隔,毫秒 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, int intervalMS, Action action) + { + return new LoopAction(count, TimeSpan.FromMilliseconds(intervalMS), action); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, Action action) + { + return CreateLoopAction(count, TimeSpan.Zero, action); + } + + /// + /// 创建可循环操作体 + /// + /// 每次循环间隔 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(TimeSpan interval, Action action) + { + return CreateLoopAction(-1, interval, action); + } + + /// + /// 创建可循环操作体 + /// + /// 执行委托 + /// + public static LoopAction CreateLoopAction(Action action) + { + return CreateLoopAction(-1, TimeSpan.Zero, action); + } + + /// + /// 已执行次数 + /// + public int ExecutedCount => executedCount; + + /// + /// 执行间隔 + /// + public TimeSpan Interval => m_interval; + + /// + /// 循环次数 + /// + public int LoopCount => m_loopCount; + + private readonly Action action; + + /// + /// 执行委托 + /// + public Action ExecuteAction => action; + + private RunStatus runStatus; + + /// + /// 是否在运行 + /// + public RunStatus RunStatus => runStatus; + + /// + /// 运行 + /// + public void Run() + { + if (runStatus == RunStatus.None) + { + runStatus = RunStatus.Running; + if (m_loopCount >= 0) + { + for (int i = 0; i < m_loopCount; i++) + { + if (runStatus == RunStatus.Disposed) + { + return; + } + action.Invoke(this); + executedCount++; + if (runStatus == RunStatus.Paused) + { + m_waitHandle.WaitOne(); + } + m_waitHandle.WaitOne(m_interval); + } + } + else + { + while (true) + { + if (runStatus == RunStatus.Disposed) + { + return; + } + action.Invoke(this); + executedCount++; + if (runStatus == RunStatus.Paused) + { + m_waitHandle.WaitOne(); + } + m_waitHandle.WaitOne(m_interval); + } + } + runStatus = RunStatus.Completed; + } + } + + /// + /// 重新运行 + /// + public void Rerun() + { + if (runStatus == RunStatus.Disposed) + { + throw new Exception("无法利用已释放的资源"); + } + runStatus = RunStatus.None; + Run(); + } + + /// + /// 以异步重新运行 + /// + /// + public Task RerunAsync() + { + if (runStatus == RunStatus.Disposed) + { + throw new Exception("无法利用已释放的资源"); + } + runStatus = RunStatus.None; + return RunAsync(); + } + + /// + /// 以异步运行 + /// + /// + public Task RunAsync() + { + return EasyTask.Run(() => + { + Run(); + }); + } + + /// + /// 暂停 + /// + public void Pause() + { + if (runStatus == RunStatus.Running) + { + m_waitHandle.Reset(); + runStatus = RunStatus.Paused; + } + } + + /// + /// 回复 + /// + public void Resume() + { + if (runStatus == RunStatus.Paused) + { + runStatus = RunStatus.Running; + m_waitHandle.Set(); + } + } + + /// + /// 释放资源 + /// + public void Dispose() + { + if (runStatus == RunStatus.Disposed) + { + return; + } + if (runStatus == RunStatus.Completed) + { + m_waitHandle.Dispose(); + } + runStatus = RunStatus.Disposed; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs.meta new file mode 100644 index 0000000..9580546 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/LoopAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81790d8c0e90bab4e93c77eaffa710a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs new file mode 100644 index 0000000..8fba5fc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 运行状态 + /// + public enum RunStatus : byte + { + /// + /// None + /// + None, + + /// + /// Running + /// + Running, + + /// + /// Completed + /// + Completed, + + /// + /// Pause + /// + Paused, + + /// + /// Disposed + /// + Disposed + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs.meta new file mode 100644 index 0000000..37af46e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Action/RunStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b33379cff145d2438e3361cd70b4cb6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message.meta new file mode 100644 index 0000000..124c34f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c25c2b186b529a24cb19dace7352c939 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs new file mode 100644 index 0000000..e45f437 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 注册为消息 + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)] + public sealed class AppMessageAttribute : Attribute + { + /// + /// 构造函数 + /// + public AppMessageAttribute() + { + } + + /// + /// 构造函数 + /// + /// + public AppMessageAttribute(string token) + { + Token = token; + } + + /// + /// 标识 + /// + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs.meta new file mode 100644 index 0000000..d063eec --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessageAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8e8847df71b35042933749553acc233 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs new file mode 100644 index 0000000..75f1303 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs @@ -0,0 +1,269 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 消息通知类。内部全为弱引用。 + /// + public class AppMessenger + { + private static AppMessenger m_instance; + private readonly ReaderWriterLockSlim m_lockSlim = new ReaderWriterLockSlim(); + private readonly Dictionary> m_tokenAndInstance = new Dictionary>(); + + /// + /// 默认单例实例 + /// + public static AppMessenger Default + { + get + { + if (m_instance != null) + { + return m_instance; + } + lock (typeof(AppMessenger)) + { + if (m_instance != null) + { + return m_instance; + } + m_instance = new AppMessenger(); + return m_instance; + } + } + } + + /// + /// 允许多广播注册 + /// + public bool AllowMultiple { get; set; } + + /// + /// 添加 + /// + /// + /// + /// + public void Add(string token, MessageInstance messageInstance) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + if (m_tokenAndInstance.ContainsKey(token)) + { + if (!AllowMultiple) + { + throw new MessageRegisteredException(TouchSocketStatus.TokenExisted.GetDescription(token)); + } + m_tokenAndInstance[token].Add(messageInstance); + } + else + { + m_tokenAndInstance.Add(token, new List() + { + messageInstance + }); + } + } + } + + /// + /// 判断能否触发该消息,意味着该消息是否已经注册。 + /// + /// + /// + public bool CanSendMessage(string token) + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + return m_tokenAndInstance.ContainsKey(token); + } + } + + /// + /// 清除所有消息 + /// + public void Clear() + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + m_tokenAndInstance.Clear(); + } + } + + /// + /// 获取所有消息 + /// + /// + public string[] GetAllMessage() + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + return m_tokenAndInstance.Keys.ToArray(); + } + } + + /// + /// 移除 + /// + /// + public void Remove(string token) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + m_tokenAndInstance.Remove(token); + } + } + + /// + /// 按对象移除 + /// + /// + public void Remove(IMessageObject messageObject) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + List key = new List(); + + foreach (var item in m_tokenAndInstance.Keys) + { + foreach (var item2 in m_tokenAndInstance[item].ToArray()) + { + if (messageObject == item2.MessageObject) + { + m_tokenAndInstance[item].Remove(item2); + if (m_tokenAndInstance[item].Count == 0) + { + key.Add(item); + } + } + } + } + + foreach (var item in key) + { + m_tokenAndInstance.Remove(item); + } + } + } + + /// + /// 发送消息 + /// + /// + /// + /// + public Task SendAsync(string token, params object[] parameters) + { + return EasyTask.Run(() => + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + if (m_tokenAndInstance.TryGetValue(token, out List list)) + { + List clear = new List(); + + foreach (var item in list) + { + if (!item.Static && !item.WeakReference.TryGetTarget(out _)) + { + clear.Add(item); + continue; + } + try + { + item.Invoke(item.MessageObject, parameters); + } + catch + { + } + } + + foreach (var item in clear) + { + list.Remove(item); + } + } + else + { + throw new MessageNotFoundException(TouchSocketStatus.MessageNotFound.GetDescription(token)); + } + } + }); + } + + /// + /// 发送消息,当多播时,只返回最后一个返回值 + /// + /// 返回值类型 + /// + /// + /// + /// + public Task SendAsync(string token, params object[] parameters) + { + return EasyTask.Run(() => + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + if (m_tokenAndInstance.TryGetValue(token, out List list)) + { + T result = default; + List clear = new List(); + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + if (!item.Static && !item.WeakReference.TryGetTarget(out _)) + { + clear.Add(item); + continue; + } + + try + { + if (i == list.Count - 1) + { + result = (T)item.Invoke(item.MessageObject, parameters); + } + else + { + item.Invoke(item.MessageObject, parameters); + } + } + catch + { + } + } + + foreach (var item in clear) + { + list.Remove(item); + } + return result; + } + else + { + throw new MessageNotFoundException(TouchSocketStatus.MessageNotFound.GetDescription(token)); + } + } + }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs.meta new file mode 100644 index 0000000..31b683b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessenger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c012b6c297e10234c9a984c5de182ef9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs new file mode 100644 index 0000000..e704258 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs @@ -0,0 +1,321 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// AppMessengerExtensions + /// + public static class AppMessengerExtensions + { + /// + /// 注册类的静态消息 + /// + /// + public static void Register(this AppMessenger appMessenger) where T : IMessageObject + { + Type type = typeof(T); + Register(appMessenger, type); + } + + /// + /// 注册类的静态消息 + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Type type) + { + MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Default); + foreach (var method in methods) + { + IEnumerable attributes = method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (string.IsNullOrEmpty(att.Token)) + { + Register(appMessenger, null, method.Name, method); + } + else + { + Register(appMessenger, null, att.Token, method); + } + } + } + } + } + + /// + /// 注册消息 + /// + /// + /// + public static void Register(this AppMessenger appMessenger, IMessageObject messageObject) + { + MethodInfo[] methods = messageObject.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Default); + foreach (var method in methods) + { + IEnumerable attributes = method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (string.IsNullOrEmpty(att.Token)) + { + Register(appMessenger, messageObject, method.Name, method); + } + else + { + Register(appMessenger, messageObject, att.Token, method); + } + } + } + } + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, IMessageObject messageObject, string token, MethodInfo methodInfo) + { + appMessenger.Add(token, new MessageInstance(methodInfo, messageObject)); + } + + /// + /// 注册消息 + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 卸载消息 + /// + /// + /// + public static void Unregister(this AppMessenger appMessenger, IMessageObject messageObject) + { + appMessenger.Remove(messageObject); + } + + /// + /// 移除注册 + /// + /// + /// + /// + public static void Unregister(this AppMessenger appMessenger, string token) + { + if (token is null) + { + throw new ArgumentNullException(nameof(token)); + } + appMessenger.Remove(token); + } + + private static void RegisterDelegate(this AppMessenger appMessenger, string token, Delegate dele) + { + IEnumerable attributes = dele.Method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (token.IsNullOrEmpty()) + { + if (string.IsNullOrEmpty(att.Token)) + { + token = dele.Method.Name; + } + else + { + token = att.Token; + } + } + + appMessenger.Add(token, new MessageInstance(dele.Method, dele.Target)); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs.meta new file mode 100644 index 0000000..a5b8f6d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5121ee83ba9e037469260feb5d424709 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs new file mode 100644 index 0000000..d66bfe8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 限定消息的接口 + /// + public interface IMessageObject + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs.meta new file mode 100644 index 0000000..9f8d2db --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/IMessageObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aae57b2f7cb262a4aa2322b2b514ee40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs new file mode 100644 index 0000000..b89301c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// MessageInstance + /// + public class MessageInstance : Method + { + private readonly WeakReference weakReference; + + /// + /// MessageInstance + /// + /// + /// + public MessageInstance(MethodInfo method, object messageObject) : base(method) + { + weakReference = new WeakReference(messageObject); + } + + /// + /// 承载消息的实体 + /// + public object MessageObject + { + get + { + weakReference.TryGetTarget(out var target); + return target; + } + } + + /// + /// 弱引用。 + /// + public WeakReference WeakReference => weakReference; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs.meta new file mode 100644 index 0000000..a1e3994 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Message/MessageInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a690d2e2227d35243ada16c135737ec0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers.meta new file mode 100644 index 0000000..a262876 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a542b7777275004487674ac0de80b79 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs new file mode 100644 index 0000000..4ec575d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs @@ -0,0 +1,175 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 不可重入的Timer + /// + public class SingleTimer : DisposableObject + { + private readonly Action m_action1; + private readonly Action m_action2; + private readonly object m_state; + private readonly Timer m_timer; + private readonly Action m_action3; + private int m_signal = 1; + + /// + /// 是否暂停执行。 + /// + public bool Pause { get; set; } + + /// + /// 自启动以来执行的次数。 + /// + public long Count { get; private set; } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action3 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, null, TimeSpan.Zero, period); + m_action3 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action1 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action2 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, state, TimeSpan.Zero, period); + m_action1 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, state, TimeSpan.Zero, period); + m_action2 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, int period, Action action) + { + m_timer = new Timer(OnTimer, state, 0, period); + m_action1 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, int period, Action action) + { + m_timer = new Timer(OnTimer, state, 0, period); + m_action2 = action; + m_state = state; + } + + private void OnTimer(object state) + { + if (Pause) + { + return; + } + if (Interlocked.Decrement(ref m_signal) == 0) + { + try + { + Count++; + m_action1?.Invoke(this); + m_action2?.Invoke(this, m_state); + m_action3?.Invoke(); + } + catch + { + } + finally + { + m_signal = 1; + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs.meta new file mode 100644 index 0000000..1deb4b8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/Timers/SingleTimer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4139602b63e760f46bd2bd3e616c44a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool.meta new file mode 100644 index 0000000..77e2e16 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4cfdf7c5bab152e4b93d00a351193534 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs new file mode 100644 index 0000000..78e77bd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 等待返回类 + /// + public interface IWaitResult + { + /// + /// 消息 + /// + string Message { get; set; } + + /// + /// 标记 + /// + long Sign { get; set; } + + /// + /// 状态 + /// + byte Status { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs.meta new file mode 100644 index 0000000..b2b54e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/IWaitResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e2fb6dc7a66e1b43828068f088f685d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs new file mode 100644 index 0000000..c2798d0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// ValueWaitResult + /// + [Serializable] + public struct ValueWaitResult : IWaitResult + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + /// 标记号 + /// + public long Sign { get; set; } + + /// + /// 状态 + /// + public byte Status { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs.meta new file mode 100644 index 0000000..1cf507b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1344806cfec2543438a779d6e839df15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs new file mode 100644 index 0000000..a013410 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 等待数据对象 + /// + /// + public class WaitData : DisposableObject + { + private readonly AutoResetEvent m_waitHandle; + private WaitDataStatus m_status; + private T m_waitResult; + + /// + /// 构造函数 + /// + public WaitData() + { + m_waitHandle = new AutoResetEvent(false); + } + + /// + /// 延迟模式 + /// + public bool DelayModel { get; set; } + + /// + /// 状态 + /// + public WaitDataStatus Status => m_status; + + /// + /// 等待数据结果 + /// + public T WaitResult => m_waitResult; + + /// + /// 取消任务 + /// + public void Cancel() + { + m_status = WaitDataStatus.Canceled; + if (!DelayModel) + { + m_waitHandle.Set(); + } + } + + /// + /// Reset。 + /// 设置为null。然后重置状态为,waitHandle.Reset() + /// + public bool Reset() + { + m_status = WaitDataStatus.Default; + m_waitResult = default; + if (!DelayModel) + { + return m_waitHandle.Reset(); + } + return true; + } + + /// + /// 使等待的线程继续执行 + /// + public bool Set() + { + m_status = WaitDataStatus.SetRunning; + if (!DelayModel) + { + return m_waitHandle.Set(); + } + return true; + } + + /// + /// 使等待的线程继续执行 + /// + /// 等待结果 + public bool Set(T waitResult) + { + m_waitResult = waitResult; + m_status = WaitDataStatus.SetRunning; + if (!DelayModel) + { + return m_waitHandle.Set(); + } + return true; + } + + /// + /// 加载取消令箭 + /// + /// + public void SetCancellationToken(CancellationToken cancellationToken) + { + if (cancellationToken.CanBeCanceled) + { + cancellationToken.Register(Cancel); + } + } + + /// + /// 载入结果 + /// + public void SetResult(T result) + { + m_waitResult = result; + } + + /// + /// 等待指定时间 + /// + /// + public WaitDataStatus Wait(TimeSpan timeSpan) + { + return this.Wait((int)timeSpan.TotalMilliseconds); + } + + /// + /// 等待指定毫秒 + /// + /// + public WaitDataStatus Wait(int millisecond) + { + if (DelayModel) + { + for (int i = 0; i < millisecond / 10.0; i++) + { + if (m_status != WaitDataStatus.Default) + { + return m_status; + } + Task.Delay(10).GetAwaiter().GetResult(); + } + m_status = WaitDataStatus.Overtime; + return m_status; + } + else + { + if (!m_waitHandle.WaitOne(millisecond)) + { + m_status = WaitDataStatus.Overtime; + } + return m_status; + } + } + + /// + /// 等待指定时间 + /// + /// + /// + public Task WaitAsync(TimeSpan timeSpan) + { + return this.WaitAsync((int)timeSpan.TotalMilliseconds); + } + + /// + /// 等待指定毫秒 + /// + /// + public async Task WaitAsync(int millisecond) + { + if (DelayModel) + { + for (int i = 0; i < millisecond / 10.0; i++) + { + if (m_status != WaitDataStatus.Default) + { + return m_status; + } + await Task.Delay(10); + } + m_status = WaitDataStatus.Overtime; + return m_status; + } + else + { + if (!m_waitHandle.WaitOne(millisecond)) + { + m_status = WaitDataStatus.Overtime; + } + return m_status; + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_status = WaitDataStatus.Disposed; + m_waitResult = default; + m_waitHandle.SafeDispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs.meta new file mode 100644 index 0000000..08d836a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd63f14d7578a034c93cb934f020356f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs new file mode 100644 index 0000000..49aef1e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 等待数据状态 + /// + public enum WaitDataStatus : byte + { + /// + /// 默认 + /// + Default, + + /// + /// 收到信号运行 + /// + SetRunning, + + /// + /// 超时 + /// + Overtime, + + /// + /// 已取消 + /// + Canceled, + + /// + /// 已释放 + /// + Disposed + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs.meta new file mode 100644 index 0000000..68dd01d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc80deeeb66643848ba2bb75f6eef547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs new file mode 100644 index 0000000..7faf478 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs @@ -0,0 +1,191 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 等待处理数据 + /// + /// + public class WaitHandlePool : DisposableObject where T : IWaitResult + { + private readonly ConcurrentDictionary> m_waitDic; + private readonly ConcurrentQueue> m_waitQueue; + + /// + /// 构造函数 + /// + public WaitHandlePool() + { + m_waitDic = new ConcurrentDictionary>(); + m_waitQueue = new ConcurrentQueue>(); + } + + /// + /// 销毁 + /// + /// + public void Destroy(WaitData waitData) + { + if (waitData.DisposedValue) + { + return; + } + if (m_waitDic.TryRemove(waitData.WaitResult.Sign, out _)) + { + waitData.Reset(); + m_waitQueue.Enqueue(waitData); + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + foreach (var item in m_waitDic.Values) + { + item.SafeDispose(); + } + foreach (var item in m_waitQueue) + { + item.SafeDispose(); + } + m_waitDic.Clear(); + + m_waitQueue.Clear(); + base.Dispose(disposing); + } + + /// + /// 取消全部 + /// + public void CancelAll() + { + foreach (var item in m_waitDic.Values) + { + item.Cancel(); + } + } + + /// + /// 延迟模式 + /// + public bool DelayModel { get; set; } = false; + + private long m_waitCount; + private long m_waitReverseCount; + + /// + /// 获取一个可等待对象 + /// + /// + /// 设置为false时,不会生成sign + /// + public WaitData GetWaitData(T result, bool autoSign = true) + { + if (m_waitQueue.TryDequeue(out var waitData)) + { + if (autoSign) + { + result.Sign = Interlocked.Increment(ref m_waitCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + waitData = new WaitData(); + waitData.DelayModel = DelayModel; + if (autoSign) + { + result.Sign = Interlocked.Increment(ref m_waitCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + /// + /// 获取一个Sign为负数的可等待对象 + /// + /// + /// 设置为false时,不会生成sign + /// + public WaitData GetReverseWaitData(T result, bool autoSign = true) + { + if (m_waitQueue.TryDequeue(out var waitData)) + { + if (autoSign) + { + result.Sign = Interlocked.Decrement(ref m_waitReverseCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + waitData = new WaitData(); + waitData.DelayModel = DelayModel; + if (autoSign) + { + result.Sign = Interlocked.Decrement(ref m_waitReverseCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + /// + /// 让等待对象恢复运行 + /// + /// + public void SetRun(long sign) + { + if (m_waitDic.TryGetValue(sign, out WaitData waitData)) + { + waitData.Set(); + } + } + + /// + /// 让等待对象恢复运行 + /// + /// + /// + public void SetRun(long sign, T waitResult) + { + if (m_waitDic.TryGetValue(sign, out WaitData waitData)) + { + waitData.Set(waitResult); + } + } + + /// + /// 让等待对象恢复运行 + /// + /// + public void SetRun(T waitResult) + { + if (m_waitDic.TryGetValue(waitResult.Sign, out WaitData waitData)) + { + waitData.Set(waitResult); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs.meta new file mode 100644 index 0000000..4235202 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20446640736161048ac306d1cf8bd0a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs new file mode 100644 index 0000000..f6787b4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 等待返回类 + /// + [Serializable] + public class WaitResult : IWaitResult + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + /// 标记号 + /// + public long Sign { get; set; } + + /// + /// 状态 + /// + public byte Status { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs.meta new file mode 100644 index 0000000..6c5bab5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Run/WaitPool/WaitResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2be68e8bcf09f2438469d6e90c97fd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization.meta new file mode 100644 index 0000000..7a8fd5d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45376e30cd7e74b43ababa5fce4665e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes.meta new file mode 100644 index 0000000..8bd64b9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aaa39ea493b93e44b8ab909f981b677a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs new file mode 100644 index 0000000..4c3572b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// FastConverterAttribute + /// + public class FastConverterAttribute : Attribute + { + /// + /// FastConverterAttribute + /// + /// + public FastConverterAttribute(Type type) + { + Type = type; + } + + /// + /// 转化器类型。 + /// + public Type Type { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs.meta new file mode 100644 index 0000000..66ed90d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4996907e912704c448f3f1d20dc9f920 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs new file mode 100644 index 0000000..5a9b709 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 忽略的Fast序列化 + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class FastNonSerializedAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs.meta new file mode 100644 index 0000000..d3f2d3e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1be39ff16225cf14dbace409a8135b25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs new file mode 100644 index 0000000..c3b79e7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 强制Fast序列化。一般当某个属性为只读时,使用该特性。 + /// + [AttributeUsage(AttributeTargets.Property)] + public class FastSerializedAttribute: Attribute + { + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs.meta new file mode 100644 index 0000000..71be18c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3871c6c503ad9db4bad42c9236ccde51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary.meta new file mode 100644 index 0000000..e5a5600 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b1725027e845914ead62e168afd5dbc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs new file mode 100644 index 0000000..8413b33 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs @@ -0,0 +1,675 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 快速二进制序列化。 + /// + public static class FastBinaryFormatter + { + static FastBinaryFormatter() + { + AddFastBinaryConverter(); + } + private static readonly ConcurrentDictionary m_instanceCache = new ConcurrentDictionary(); + + /// + /// 添加转换器。 + /// + public static void AddFastBinaryConverter() where TConverter : IFastBinaryConverter, new() + { + AddFastBinaryConverter(typeof(TType), (IFastBinaryConverter)Activator.CreateInstance(typeof(TConverter))); + } + + /// + /// 添加转换器。 + /// + /// + /// + public static void AddFastBinaryConverter(IFastBinaryConverter converter) + { + AddFastBinaryConverter(typeof(TType), converter); + } + + /// + /// 添加转换器。 + /// + /// + /// + public static void AddFastBinaryConverter(Type type, IFastBinaryConverter converter) + { + m_instanceCache.AddOrUpdate(type, new SerializObject(type) { Converter = converter }, (k, v) => v); + } + + #region Serialize + + /// + /// 序列化对象 + /// + /// 流 + /// 对象 + public static void Serialize(ByteBlock byteBlock, T graph) + { + byteBlock.Position = 1; + SerializeObject(byteBlock, graph); + byteBlock.Buffer[0] = 1; + byteBlock.SetLength(byteBlock.Position); + } + + private static int SerializeClass(ByteBlock stream, T obj, Type type) + { + int len = 0; + if (obj != null) + { + SerializObject serializObject = GetOrAddInstance(type); + + for (int i = 0; i < serializObject.MemberInfos.Length; i++) + { + MemberInfo memberInfo = serializObject.MemberInfos[i]; + byte[] propertyBytes = Encoding.UTF8.GetBytes(memberInfo.Name); + if (propertyBytes.Length > byte.MaxValue) + { + throw new Exception($"属性名:{memberInfo.Name}超长"); + } + stream.Write((byte)propertyBytes.Length); + stream.Write(propertyBytes, 0, propertyBytes.Length); + len += propertyBytes.Length + 1; + //len += SerializeObject(stream, property.GetValue(obj)); + len += SerializeObject(stream, serializObject.MemberAccessor.GetValue(obj, memberInfo.Name)); + } + //foreach (PropertyInfo property in serializObject.Properties) + //{ + //} + + //foreach (FieldInfo fieldInfo in serializObject.FieldInfos) + //{ + // byte[] propertyBytes = Encoding.UTF8.GetBytes(fieldInfo.Name); + // if (propertyBytes.Length > byte.MaxValue) + // { + // throw new Exception($"属性名:{fieldInfo.Name}超长"); + // } + // byte lenBytes = (byte)propertyBytes.Length; + // stream.Write(lenBytes); + // stream.Write(propertyBytes, 0, propertyBytes.Length); + // len += propertyBytes.Length + 1; + // len += SerializeObject(stream, fieldInfo.GetValue(obj)); + //} + } + return len; + } + + private static int SerializeDictionary(ByteBlock stream, IEnumerable param) + { + int len = 0; + if (param != null) + { + long oldPosition = stream.Position; + stream.Position += 4; + len += 4; + uint paramLen = 0; + + foreach (dynamic item in param) + { + len += SerializeObject(stream, item.Key); + len += SerializeObject(stream, item.Value); + paramLen++; + } + long newPosition = stream.Position; + stream.Position = oldPosition; + stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen)); + stream.Position = newPosition; + } + return len; + } + + private static int SerializeIListOrArray(ByteBlock stream, IEnumerable param) + { + int len = 0; + if (param != null) + { + long oldPosition = stream.Position; + stream.Position += 4; + len += 4; + uint paramLen = 0; + + foreach (object item in param) + { + paramLen++; + len += SerializeObject(stream, item); + } + long newPosition = stream.Position; + stream.Position = oldPosition; + stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen)); + stream.Position = newPosition; + } + return len; + } + + private static int SerializeObject(ByteBlock byteBlock, T graph) + { + int len = 0; + byte[] data = null; + + long startPosition = byteBlock.Position; + long endPosition; + if (graph != null) + { + Type type = graph.GetType(); + if (type.IsPrimitive) + { + switch (graph) + { + case byte value: + { + data = new byte[] { value }; + break; + } + case sbyte value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case bool value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case short value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case ushort value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case int value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case uint value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case long value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case ulong value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case float value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case double value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case char value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + default: + { + throw new Exception("未知基础类型"); + } + } + } + else + { + switch (graph) + { + case string value: + { + data = Encoding.UTF8.GetBytes(value); + break; + } + case DateTime value: + { + data = TouchSocketBitConverter.Default.GetBytes(value.Ticks); + break; + } + case Enum _: + { + var enumValType = Enum.GetUnderlyingType(type); + + if (enumValType == TouchSocketCoreUtility.byteType) + { + data = new byte[] { Convert.ToByte(graph) }; + } + else if (enumValType == TouchSocketCoreUtility.shortType) + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt16(graph)); + } + else if (enumValType == TouchSocketCoreUtility.intType) + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt32(graph)); + } + else + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt64(graph)); + } + break; + } + case byte[] value: + { + data = value; + break; + } + default: + { + byteBlock.Position += 4; + var serializeObj = GetOrAddInstance(type); + if (serializeObj.Converter != null) + { + len += serializeObj.Converter.Write(byteBlock, graph); + } + else + { + switch (serializeObj.InstanceType) + { + case InstanceType.List: + len += SerializeIListOrArray(byteBlock, (IEnumerable)graph); + break; + + case InstanceType.Array: + len += SerializeIListOrArray(byteBlock, (IEnumerable)graph); + break; + + case InstanceType.Dictionary: + len += SerializeDictionary(byteBlock, (IEnumerable)graph); + break; + + default: + case InstanceType.Class: + len += SerializeClass(byteBlock, graph, type); + break; + } + } + break; + } + } + } + + if (data != null) + { + len = data.Length; + endPosition = len + startPosition + 4; + } + else + { + endPosition = byteBlock.Position; + } + } + else + { + endPosition = startPosition + 4; + } + + byte[] lenBuffer = TouchSocketBitConverter.Default.GetBytes(len); + byteBlock.Position = startPosition; + byteBlock.Write(lenBuffer, 0, lenBuffer.Length); + + if (data != null) + { + byteBlock.Write(data, 0, data.Length); + } + byteBlock.Position = endPosition; + return len + 4; + } + + #endregion Serialize + + #region Deserialize + + /// + /// 反序列化 + /// + /// + /// + /// + /// + public static object Deserialize(byte[] data, int offset, Type type) + { + if (data[offset] != 1) + { + throw new Exception("Fast反序列化数据流解析错误。"); + } + offset += 1; + return Deserialize(type, data, ref offset); + } + + private static object Deserialize(Type type, byte[] datas, ref int offset) + { + bool nullable = type.IsNullableType(); + if (nullable) + { + type = type.GenericTypeArguments[0]; + } + dynamic obj; + int len = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + if (len > 0) + { + if (type == TouchSocketCoreUtility.stringType) + { + obj = Encoding.UTF8.GetString(datas, offset, len); + } + else if (type == TouchSocketCoreUtility.byteType) + { + obj = datas[offset]; + } + else if (type == TouchSocketCoreUtility.sbyteType) + { + obj = (sbyte)(TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.boolType) + { + obj = (TouchSocketBitConverter.Default.ToBoolean(datas, offset)); + } + else if (type == TouchSocketCoreUtility.shortType) + { + obj = (TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.ushortType) + { + obj = (TouchSocketBitConverter.Default.ToUInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.intType) + { + obj = (TouchSocketBitConverter.Default.ToInt32(datas, offset)); + } + else if (type == TouchSocketCoreUtility.uintType) + { + obj = (TouchSocketBitConverter.Default.ToUInt32(datas, offset)); + } + else if (type == TouchSocketCoreUtility.longType) + { + obj = (TouchSocketBitConverter.Default.ToInt64(datas, offset)); + } + else if (type == TouchSocketCoreUtility.ulongType) + { + obj = (TouchSocketBitConverter.Default.ToUInt64(datas, offset)); + } + else if (type == TouchSocketCoreUtility.floatType) + { + obj = (TouchSocketBitConverter.Default.ToSingle(datas, offset)); + } + else if (type == TouchSocketCoreUtility.doubleType) + { + obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset)); + } + else if (type == TouchSocketCoreUtility.decimalType) + { + obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset)); + } + else if (type == TouchSocketCoreUtility.charType) + { + obj = (TouchSocketBitConverter.Default.ToChar(datas, offset)); + } + else if (type == TouchSocketCoreUtility.dateTimeType) + { + obj = (new DateTime(TouchSocketBitConverter.Default.ToInt64(datas, offset))); + } + else if (type.BaseType == typeof(Enum)) + { + Type enumType = Enum.GetUnderlyingType(type); + + if (enumType == typeof(byte)) + { + obj = Enum.ToObject(type, datas[offset]); + } + else if (enumType == typeof(short)) + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (enumType == typeof(int)) + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt32(datas, offset)); + } + else + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt64(datas, offset)); + } + } + else if (type == TouchSocketCoreUtility.bytesType) + { + byte[] data = new byte[len]; + Buffer.BlockCopy(datas, offset, data, 0, len); + obj = data; + } + else if (type.IsClass || type.IsStruct()) + { + var serializeObj = GetOrAddInstance(type); + if (serializeObj.Converter != null) + { + obj = serializeObj.Converter.Read(datas, offset, len); + } + else + { + obj = DeserializeClass(type, datas, offset, len); + } + } + else + { + throw new Exception("未定义的类型:" + type.ToString()); + } + } + else + { + if (nullable) + { + obj = null; + } + else + { + obj = type.GetDefault(); + } + } + offset += len; + return obj; + } + + private static object DeserializeClass(Type type, byte[] datas, int offset, int length) + { + SerializObject serializObject = GetOrAddInstance(type); + + object instance; + switch (serializObject.InstanceType) + { + case InstanceType.Class: + { + instance = serializObject.GetNewInstance(); + int index = offset; + while (offset - index < length && (length >= 4)) + { + int len = datas[offset]; + string propertyName = Encoding.UTF8.GetString(datas, offset + 1, len); + offset += len + 1; + if (serializObject.IsStruct) + { + if (serializObject.PropertiesDic.ContainsKey(propertyName)) + { + PropertyInfo property = serializObject.PropertiesDic[propertyName]; + object obj = Deserialize(property.PropertyType, datas, ref offset); + property.SetValue(instance, obj); + } + else if (serializObject.FieldInfosDic.ContainsKey(propertyName)) + { + FieldInfo property = serializObject.FieldInfosDic[propertyName]; + object obj = Deserialize(property.FieldType, datas, ref offset); + property.SetValue(instance, obj); + } + else + { + int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + offset += pLen; + } + } + else + { + if (serializObject.PropertiesDic.TryGetValue(propertyName, out PropertyInfo property)) + { + object obj = Deserialize(property.PropertyType, datas, ref offset); + serializObject.MemberAccessor.SetValue(instance, property.Name, obj); + } + else if (serializObject.FieldInfosDic.TryGetValue(propertyName, out FieldInfo fieldInfo)) + { + object obj = Deserialize(fieldInfo.FieldType, datas, ref offset); + serializObject.MemberAccessor.SetValue(instance, fieldInfo.Name, obj); + } + else + { + int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + offset += pLen; + } + } + } + break; + } + case InstanceType.List: + { + instance = serializObject.GetNewInstance(); + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object obj = Deserialize(serializObject.ArgTypes[0], datas, ref offset); + serializObject.AddMethod.Invoke(instance, new object[] { obj }); + } + } + else + { + instance = null; + } + break; + } + case InstanceType.Array: + { + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + Array array = Array.CreateInstance(serializObject.ArrayType, paramLen); + + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object obj = Deserialize(serializObject.ArrayType, datas, ref offset); + array.SetValue(obj, i); + } + instance = array; + } + else + { + instance = null; + } + break; + } + case InstanceType.Dictionary: + { + instance = serializObject.GetNewInstance(); + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object key = Deserialize(serializObject.ArgTypes[0], datas, ref offset); + object value = Deserialize(serializObject.ArgTypes[1], datas, ref offset); + if (key != null) + { + serializObject.AddMethod.Invoke(instance, new object[] { key, value }); + } + } + + //uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + //offset += 4; + //for (uint i = 0; i < paramLen; i++) + //{ + // offset += 4; + // offset += datas[offset] + 1; + // object key = this.Deserialize(instanceObject.ArgTypes[0], datas, ref offset); + + // offset += datas[offset] + 1; + // object value = this.Deserialize(instanceObject.ArgTypes[1], datas, ref offset); + // if (key != null) + // { + // instanceObject.AddMethod.Invoke(instance, new object[] { key, value }); + // } + //} + } + else + { + instance = null; + } + break; + } + default: + instance = null; + break; + } + + return instance; + } + + #endregion Deserialize + + private static SerializObject GetOrAddInstance(Type type) + { + if (m_instanceCache.TryGetValue(type, out SerializObject instance)) + { + return instance; + } + if (type.IsArray)//数组 + { + SerializObject instanceObject = new SerializObject(type); + m_instanceCache.TryAdd(type, instanceObject); + return instanceObject; + } + else if (type.IsClass || type.IsStruct()) + { + if (type.IsNullableType()) + { + type = type.GetGenericArguments()[0]; + } + + SerializObject instanceObject = new SerializObject(type); + m_instanceCache.TryAdd(type, instanceObject); + return instanceObject; + } + return null; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs.meta new file mode 100644 index 0000000..f96767a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aef68afd06450e24db0df77534941edc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs new file mode 100644 index 0000000..fe937a5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// FastBinary转换器 + /// + public interface IFastBinaryConverter + { + /// + /// 读取对象,不需要考虑为null的情况。 + /// + /// + /// + /// + /// + public object Read(byte[] buffer, int offset, int len); + + /// + /// 写入对象,不需要考虑为null的情况。 + /// + /// + /// + public int Write(ByteBlock byteBlock, object obj); + } + + /// + /// FastBinary转换器 + /// + /// + public abstract class FastBinaryConverter : IFastBinaryConverter + { + int IFastBinaryConverter.Write(ByteBlock byteBlock, object obj) + { + return Write(byteBlock, (T)obj); + } + + object IFastBinaryConverter.Read(byte[] buffer, int offset, int len) + { + return Read(buffer, offset, len); + } + + /// + /// 写入对象,不需要考虑为null的情况。 + /// + /// + /// + protected abstract int Write(ByteBlock byteBlock, T obj); + + /// + /// 读取对象,不需要考虑为null的情况。 + /// + /// + /// + /// + /// + protected abstract T Read(byte[] buffer, int offset, int len); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs.meta new file mode 100644 index 0000000..25f3584 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d0bc5ff572150a4890baff6aa9fd9cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs new file mode 100644 index 0000000..7383eea --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + internal enum InstanceType + { + Class, + List, + Array, + Dictionary + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs.meta new file mode 100644 index 0000000..945aef8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e73431e2435f0b41b4f9438678737ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs new file mode 100644 index 0000000..29e080d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs @@ -0,0 +1,191 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace TouchSocket.Core +{ + internal class SerializObject + { + private MemberInfo[] m_MemberInfos; + private FieldInfo[] m_fieldInfos; + private PropertyInfo[] m_properties; + public IFastBinaryConverter Converter { get; set; } + public SerializObject(Type type) + { + Type = type; + if (type.IsArray)//数组 + { + this.InstanceType = InstanceType.Array; + this.ArrayType = type.GetElementType(); + } + else if (type.IsClass || type.IsStruct()) + { + if (type.IsNullableType()) + { + type = type.GetGenericArguments()[0]; + } + this.Type = type; + if (TouchSocketCoreUtility.listType.IsAssignableFrom(type)) + { + Type genericType = type; + while (true) + { + if (genericType.IsGenericType) + { + break; + } + genericType = genericType.BaseType; + if (genericType == TouchSocketCoreUtility.objType) + { + break; + } + } + this.ArgTypes = genericType.GetGenericArguments(); + this.AddMethod = new Method(type.GetMethod("Add")); + this.InstanceType = InstanceType.List; + } + else if (TouchSocketCoreUtility.dicType.IsAssignableFrom(type)) + { + Type genericType = type; + while (true) + { + if (genericType.IsGenericType) + { + break; + } + genericType = genericType.BaseType; + if (genericType == TouchSocketCoreUtility.objType) + { + break; + } + } + this.ArgTypes = genericType.GetGenericArguments(); + this.AddMethod = new Method(type.GetMethod("Add")); + this.InstanceType = InstanceType.Dictionary; + } + else + { + this.InstanceType = InstanceType.Class; + MemberAccessor = new MemberAccessor(type) + { + OnGetFieldInfes = GetFieldInfos, + OnGetProperties = GetProperties + }; + MemberAccessor.Build(); + } + if (type.GetCustomAttribute() is FastConverterAttribute attribute) + { + this.Converter = (IFastBinaryConverter)Activator.CreateInstance(attribute.Type); + } + this.PropertiesDic = GetProperties(type).ToDictionary(a => a.Name); + this.FieldInfosDic = GetFieldInfos(type).ToDictionary(a => a.Name); + if (type.IsGenericType) + { + this.ArgTypes = type.GetGenericArguments(); + } + } + this.IsStruct = type.IsStruct(); + } + + public bool IsStruct { get; private set; } + + public Method AddMethod { get; private set; } + + public Type[] ArgTypes { get; private set; } + + public Type ArrayType { get; private set; } + + public FieldInfo[] FieldInfos + { + get + { + m_fieldInfos ??= FieldInfosDic.Values.ToArray(); + return m_fieldInfos; + } + } + + public MemberInfo[] MemberInfos + { + get + { + if (m_MemberInfos == null) + { + List infos = new List(); + infos.AddRange(FieldInfosDic.Values); + infos.AddRange(PropertiesDic.Values); + m_MemberInfos = infos.ToArray(); + } + return m_MemberInfos; + } + } + + public Dictionary FieldInfosDic { get; private set; } + + public InstanceType InstanceType { get; private set; } + + public MemberAccessor MemberAccessor { get; private set; } + + public PropertyInfo[] Properties + { + get + { + m_properties ??= PropertiesDic.Values.ToArray(); + return m_properties; + } + } + + public Dictionary PropertiesDic { get; private set; } + + public Type Type { get; private set; } + + public object GetNewInstance() + { + return Activator.CreateInstance(Type); + } + + private static FieldInfo[] GetFieldInfos(Type type) + { + return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default) + .Where(p => + { + return !p.IsInitOnly && (!p.IsDefined(typeof(FastNonSerializedAttribute), true)); + }) + .ToArray(); + } + + private static PropertyInfo[] GetProperties(Type type) + { + return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default) + .Where(p => + { + if (p.IsDefined(typeof(FastSerializedAttribute), true)) + { + return true; + } + else + { + return p.CanWrite && + p.CanRead && + (!p.IsDefined(typeof(FastNonSerializedAttribute), true) && + (p.SetMethod.GetParameters().Length == 1) && + (p.GetMethod.GetParameters().Length == 0)); + } + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs.meta new file mode 100644 index 0000000..c195450 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a075b6de902ac0642b8bea3e43786dd6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs new file mode 100644 index 0000000..fb59f61 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 序列化类型 + /// + public enum SerializationType : byte + { + /// + /// 内置快速二进制 + /// + FastBinary, + + /// + /// Json + /// + Json, + + /// + /// Xml + /// + Xml, + + /// + /// 系统二进制。微软认为这是不安全的,所以谨慎使用。 + /// + SystemBinary + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs.meta new file mode 100644 index 0000000..e13de15 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9afbcb14756cd7d40a7fcb11a55b5cb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs new file mode 100644 index 0000000..1be42ec --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + internal class VersionFastBinaryConverter : FastBinaryConverter + { + protected override Version Read(byte[] buffer, int offset, int len) + { + ValueByteBlock byteBlock = new ValueByteBlock(buffer); + byteBlock.Pos = offset; + return new Version(byteBlock.ReadInt32(), byteBlock.ReadInt32(), byteBlock.ReadInt32(), byteBlock.ReadInt32()); + } + + protected override int Write(ByteBlock byteBlock, Version obj) + { + byteBlock.Write(obj.Major); + byteBlock.Write(obj.Minor); + byteBlock.Write(obj.Build); + byteBlock.Write(obj.Revision); + return sizeof(int) * 4; + } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs.meta new file mode 100644 index 0000000..e547c80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/FastBinary/VersionFastBinaryConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fd686751fc66a54580fbe339280d966 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json.meta new file mode 100644 index 0000000..3aec275 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4f9354b020963948b3a1c712470a25d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs new file mode 100644 index 0000000..bdafedb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs @@ -0,0 +1,830 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.Dynamic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// Json高速转换 + /// 此代码来源:https://gitee.com/majorworld + /// + public static class JsonFastConverter + { + /// + /// 全局时间序列化样式,默认为yyyy-MM-dd HH:mm:ss + /// + public static string TimeFormat = "yyyy-MM-dd HH:mm:ss"; + + /// + /// 将Json字符串转为指定类型 + /// + /// + /// + /// + public static T JsonFrom(string s) where T : class + { + return (T)JsonFrom(s, typeof(T)); + } + + /// + /// 将Json字符串转为指定类型 + /// + /// + /// + /// + /// + public static object JsonFrom(string s, Type t) + { + if (s == null) + throw new NullReferenceException("不能为null"); + StringBuilder sb = new StringBuilder(s.Length); + Dictionary dict = new Dictionary(); + List list = new List(); + int index = 0; + switch (s[0]) + { + case '{': + return s.GetObject(ref index, sb, list).ToObject(t); + + case '[': + var data = s.GetArray(ref index, sb, dict); + if (t == typeof(DataTable)) + return data.ToDataTable();//处理表类型 + if (t.GetGenericArguments().Length < 1) + { + if (t.IsArray) + JsonChange.ChangeArray(t.GetElementType(), data);//处理数组类型 + return JsonChange.ChangeData(t, data);//处理动态类型 + } + if (t.IsList()) + { + return JsonChange.ChangeList(t.GetGenericArguments()[0], data);//处理集合类型 + } + throw new NullReferenceException("类型应该为集合或数组或dynamic"); + default: + throw new NullReferenceException("第一个字符缺失{或["); + } + } + + /// + /// 将Json字符串转为对象
+ /// 重载,当前数据类型速度最快 + ///
+ /// + /// + public static Dictionary JsonFrom(string s) + { + return JsonFrom>(s); + } + + /// + /// 将对象转为Json字符串 + /// + /// + /// + /// 时间序列化样式,默认为yyyy-MM-dd HH:mm:ss + /// + public static string JsonTo(T t, string timeFormat = null) + { + StringBuilder sb = new StringBuilder(); + t.CodeObject(sb, timeFormat ?? TimeFormat); + return sb.ToString(); + } + } + + /// + /// 过滤不需要序列化的字段 + /// + public class JsonFastIgnore : Attribute + { } + + /// + /// 转换为实体类对应的类型 + /// + internal static class JsonChange + { + #region 类型判断 + + internal static bool IsDictionary(this Type type) => (typeof(IDictionary).IsAssignableFrom(type)); + + internal static bool IsList(this Type type) => (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)); + + #endregion 类型判断 + + #region 转换 + + /// + /// 处理数组类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeArray(Type type, IList data) + { + var array = Array.CreateInstance(type, data.Count); + for (int i = 0; i < data.Count; i++) + { + array.SetValue(type.ChangeData(data[i]), i); + } + return array; + } + + /// + /// 转换ArrayList类型 + /// https://gitee.com/majorworld + /// + /// + /// + internal static ArrayList ChangeArrayList(object value) + { + ArrayList array = new ArrayList(); + if (value is IList list) + { + foreach (var item in list) + array.Add(item); + } + return array; + } + + /// + /// 转换为各种数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeData(this Type p, object value) + { + if (value is Dictionary dictionary) + { + return ToObject(dictionary, p);//解析子级实体类的数据 + } + else if (p == typeof(string)) + { + return Convert.ChangeType(value, p); + } + else if (p.IsPrimitive && p != typeof(char)) + { + return Convert.ChangeType(value, p); + } + else if (p == typeof(byte[])) + { + return Convert.FromBase64String(value as string); + } + else if (p == typeof(Guid)) + { + return Guid.Parse(value as string); + } + else if (p == typeof(ArrayList)) + { + return ChangeArrayList(value);//处理动态数组类型 + } + else if (value is IList list) + { + if (p.GetGenericArguments().Length < 1) + { + if (p.IsArray) + return ChangeArray(p.GetElementType(), value as IList);//处理数组类型 + List d = new List(); + foreach (var kv in list as dynamic) + { + if (kv is Dictionary dict) + d.Add(dict.ToObject(typeof(object))); + } + return d;//解析dynamic + } + return ChangeList(p.GetGenericArguments()[0], value as List);//处理List类型 + } + return Convert.ChangeType(value, p); + } + + /// + /// 处理字典类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeDictionary(Type type, Dictionary dict) + { + //反射创建泛型字典 + var t = typeof(Dictionary<,>).MakeGenericType(new[] { type.GetGenericArguments()[0], type.GetGenericArguments()[1] }); ; + var d = Activator.CreateInstance(t) as IDictionary; + foreach (var item in dict) + d.Add(type.GetGenericArguments()[0].ChangeData(item.Key), type.GetGenericArguments()[1].ChangeData(item.Value)); + return d; + } + + /// + /// 处理集合类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeList(Type type, List data) + { + IList list = Activator.CreateInstance(typeof(List<>).MakeGenericType(type)) as IList; + foreach (var item in data) + list.Add(type.ChangeData(item)); + return list; + } + /// + /// List转DataTable + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static DataTable ToDataTable(this List list) + { + DataTable dt = new DataTable(); + for (int i = 0; i < list.Count; i++) + { + Dictionary dict = list[i] as Dictionary; + if (i == 0) + { + foreach (var item in dict) + { + dt.Columns.Add(item.Key, item.Value.GetType()); + } + } + dt.Rows.Add(dict.Values.ToArray()); + } + return dt; + } + + /// + /// 转换为对象 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ToObject(this Dictionary dict, Type type) + { + //(1/4)返回原始解析数据 + if (type == typeof(Dictionary)) + { + return dict; + } + //(2/4)返回dynamic类型数据 + if (type.UnderlyingSystemType.Name == "Object") + { + dynamic d = new ExpandoObject(); + foreach (var kv in dict) + { + if (kv.Value is Dictionary dictionary) + (d as ICollection>).Add(new KeyValuePair(kv.Key, ToObject(dictionary, typeof(object)))); + else + (d as ICollection>).Add(kv); + } + return d; + } + //(3/4)返回DataSet类型数据 + if (type == typeof(DataSet)) + { + DataSet ds = new DataSet(); + foreach (var item in dict) + { + if (item.Value is List list) + { + var dt = list.ToDataTable(); + dt.TableName = item.Key; + ds.Tables.Add(dt); + } + } + return ds; + } + //(4/4)返回所绑定的实体类数据 + var obj = Activator.CreateInstance(type); + var props = type.GetCacheInfo(); + foreach (var kv in dict) + { + var prop = props.Where(x => string.Equals(x.Name, kv.Key, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + if (prop is null) + { + if (type.IsDictionary()) + { + return ChangeDictionary(type, dict);//解析值是字典的数据(非缓存字段的字典) + } + continue; + } + if (prop.CanWrite) + { + prop.SetValue(obj, prop.PropertyType.ChangeData(kv.Value), null);//递归调用当前方法,解析子级 + } + } + return obj; + } + + private static object Go(string sValue) + { + Type type = typeof(T); + return System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(sValue.ToString()); + } + + #endregion 转换 + } + + /// + /// 解析字符串为对象 + /// + internal static class JsonDecode + { + #region 解析 + + /// + /// 解析集合 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + internal static List GetArray(this string s, ref int index, StringBuilder sb, Dictionary dict) + { + index++; + List list = new List(); + while (index < s.Length) + { + switch (s[index]) + { + case ',': + index++; + break; + + case '"': + list.Add(s.GetString(ref index, sb)); + break; + + case ']': + ++index; + return list; + + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + case '\b': + ++index; + break; + + default: + list.Add(s.GetData(s[index], ref index, sb, dict, list)); + break; + } + } + return list; + } + + /// + /// 解析对象 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + internal static Dictionary GetObject(this string s, ref int index, StringBuilder sb, List list) + { + index++; + Dictionary dict = new Dictionary(); + string key = string.Empty; + bool iskey = true; + while (index < s.Length) + { + switch (s[index]) + { + case ',': + iskey = true; + key = string.Empty; + index++; + break; + + case ':': + iskey = false; + index++; + break; + + case '}': + ++index; + return dict; + + case '"': + if (iskey) + key = s.GetString(ref index, sb); + else + dict.Add(key, s.GetString(ref index, sb)); + break; + + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + case '\b': + index++; + break; + + default: + dict.Add(key, s.GetData(s[index], ref index, sb, dict, list)); + break; + } + } + throw new FormatException("解析错误,不完整的Json"); + } + + /// + /// 获取布尔数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static bool GetBool(this string s, ref int index, bool state) + { + if (state) + { + if (s[index + 1] == 'r' && s[index + 2] == 'u' && s[index + 3] == 'e') + { + index += 4; + return true; + } + } + else + { + if (s[index + 1] == 'a' && s[index + 2] == 'l' && s[index + 3] == 's' && s[index + 4] == 'e') + { + index += 5; + return false; + } + } + throw new FormatException($"\"{string.Concat(s[index], s[index + 1], s[index + 2], s[index + 3])}\"处Json格式无法解析"); + } + + /// + /// 自动获取数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + /// + /// + private static object GetData(this string s, char c, ref int index, StringBuilder sb, Dictionary dict, List list) + { + switch (c) + { + case 't': + return s.GetBool(ref index, true); + + case 'f': + return s.GetBool(ref index, false); + + case 'n': + return s.GetNull(ref index); + + case '{': + return s.GetObject(ref index, sb, list); + + case '[': + return s.GetArray(ref index, sb, dict); + + default: + return s.GetNumber(ref index, sb); + } + } + + /// + /// 获取空数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + private static object GetNull(this string s, ref int index) + { + if (s[index + 1] == 'u' && s[index + 2] == 'l' && s[index + 3] == 'l') + { + index += 4; + return null; + } + throw new FormatException($"\"{string.Concat(s[index], s[index + 1], s[index + 2], s[index + 3])}\"处Json格式无法解析"); + } + + /// + /// 获取数字数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static object GetNumber(this string s, ref int index, StringBuilder sb) + { + sb.Clear(); + for (; index < s.Length; ++index) + { + if (s[index] == ',' || s[index] == '}' || s[index] == ']' || s[index] == ' ' || s[index] == '\n' || s[index] == '\r') + break; + else + sb.Append(s[index]); + } + string code = sb.ToString(); + if (long.TryParse(code, out long x)) + return x; + if (double.TryParse(code, out double y)) + return y; + throw new FormatException($"\"{code}\"处Json格式无法解析"); + } + + /// + /// 获取字符串数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static string GetString(this string s, ref int index, StringBuilder sb) + { + sb.Clear(); + index++; + for (; index < s.Length; ++index) + { + switch (s[index]) + { + case '"': + index++; + return sb.ToString(); + + case '\\': + if (s[index + 1] == '"' || s[index + 1] == '\\') + index++; + sb.Append(s[index]); + break; + + default: + sb.Append(s[index]); + break; + } + } + throw new FormatException($"\"{sb}\"处Json格式无法解析"); + } + + #endregion 解析 + } + + /// + /// 编码对象为字符串 + /// + internal static class JsonEncode + { + /// + /// 缓存数据加速序列化速度,主要是减少不必要的GetCustomAttributes获取特性并过滤字段 + /// + internal static ConcurrentDictionary InfoCache = new ConcurrentDictionary(); + + /// + /// 序列化 + /// + /// + /// + /// + internal static void CodeObject(this object obj, StringBuilder sb, string timeFormat) + { + bool get = true; + switch (obj) + { + case null: + sb.Append("null"); + break; + + case Enum _: + sb.Append($"{Convert.ToInt32(obj)}"); + break; + + case byte[] bytes: + sb.Append($"\"{Convert.ToBase64String(bytes)}\""); + break; + + case Array array: + sb.Append('['); + for (int i = 0; i < array.Length; i++) + { + if (i != 0) + sb.Append(","); + array.GetValue(i).CodeObject(sb, timeFormat); + } + sb.Append(']'); + break; + + case string _: + sb.Append($"\"{obj}\""); + break; + + case char _: + sb.Append($"\"{obj}\""); + break; + + case bool _: + sb.Append($"{obj.ToString().ToLower()}"); + break; + + case DataTable dt: + dt.CodeDataTable(sb, timeFormat); + break; + + case DataSet ds: + sb.Append('{'); + for (int i = 0; i < ds.Tables.Count; i++) + { + if (i != 0) + sb.Append(","); + sb.Append($"\"{ds.Tables[i].TableName}\":"); + ds.Tables[i].CodeDataTable(sb, timeFormat); + } + sb.Append('}'); + break; + + case DateTime time: + sb.AppendFormat($"\"{time.ToString(timeFormat)}\""); + break; + + case Guid id: + sb.AppendFormat($"\"{id}\""); + break; + case ArrayList list: + sb.Append('['); + for (int i = 0; i < list.Count; i++) + { + if (i != 0) + sb.Append(","); + list[i].CodeObject(sb, timeFormat); + } + sb.Append(']'); + break; + + default: + get = false; + break; + } + if (get) + return; + Type type = obj.GetType(); + //数字 + if (type.IsPrimitive && type != typeof(char)) + { + sb.Append($"{obj}"); + return; + } + //字典 + else if (type.IsDictionary()) + { + sb.Append('{'); + var collection = obj as IDictionary; + var enumerator = collection.GetEnumerator(); + int index = 0; + while (enumerator.MoveNext()) + { + if (index != 0) + sb.Append(","); + sb.Append($"\"{enumerator.Key}\":"); + enumerator.Value.CodeObject(sb, timeFormat); + index++; + } + sb.Append('}'); + return; + } + //集合 + else if (type.IsList()) + { + sb.Append('['); + if (obj is IList list) + { + for (int i = 0; i < list.Count; i++) + { + if (i != 0) + sb.Append(","); + list[i].CodeObject(sb, timeFormat); + } + } + sb.Append(']'); + return; + } + else if (type.UnderlyingSystemType.Name == "ExpandoObject") + { + sb.Append('{'); + bool first = true; + foreach (dynamic item in obj as dynamic) + { + if (!first) + sb.Append(','); + first = false; + object value = item.Value; + sb.Append($"\"{item.Key}\":"); + value.CodeObject(sb, timeFormat); + } + sb.Append('}'); + return; + } + + //对象 + var prop = type.GetCacheInfo(); + if (prop is null) + { + sb.Append("null"); + return; + } + sb.Append('{'); + for (int i = 0; i < prop.Length; i++) + { + PropertyInfo p = prop[i]; + if (i != 0) + sb.Append(","); + var data = p.GetValue(obj, null); + sb.Append($"\"{p.Name}\":"); + data.CodeObject(sb, timeFormat); + } + sb.Append("}"); + } + + /// + /// 尝试获取缓存中的类型,排除忽略的字段 + /// + /// + /// + internal static PropertyInfo[] GetCacheInfo(this Type type) + { + if (InfoCache.TryGetValue(type, out PropertyInfo[] props)) { } + else + { + props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); + List cache = new List(); + foreach (var item in props) + { + if (Attribute.GetCustomAttributes(item, typeof(JsonFastIgnore))?.Length == 0) + cache.Add(item); + } + InfoCache[type] = cache.ToArray(); + props = cache.ToArray(); + } + return props; + } + + /// + /// 序列化DataTable + /// + /// + /// + /// 时间格式化样式,默认为yyyy-MM-dd HH:mm:ss + private static void CodeDataTable(this DataTable dt, StringBuilder sb, string timeFormat) + { + sb.Append('['); + for (int i = 0; i < dt.Rows.Count; i++) + { + if (i != 0) + sb.Append(","); + var item = dt.Rows[i]; + sb.Append('{'); + for (int j = 0; j < dt.Columns.Count; j++) + { + if (j != 0) + sb.Append(","); + var cell = dt.Columns[j]; + sb.Append($"\"{cell}\":"); + item[j].CodeObject(sb, timeFormat); + } + sb.Append('}'); + } + sb.Append(']'); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs.meta new file mode 100644 index 0000000..446ac66 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonFast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f58a528cf3468f4d9d5d5be85fcffc5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs new file mode 100644 index 0000000..6b01975 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 提供Json.net无引用调用。 + /// 该代码来源:https://www.cnblogs.com/kewei/p/8228343.html + /// + internal static class JsonNet + { + /// + /// Json.Net程序集名称 + /// + private static readonly string jsonNetAssemblyName = "Newtonsoft.Json"; + + /// + /// JsonConvert类名 + /// + private static readonly string jsonNetJsonConvertTypeName = "Newtonsoft.Json.JsonConvert"; + + /// + /// 序列化方法的委托 + /// + private static Func serializeFunc = null; + + /// + /// 反序列化方法的委托 + /// + private static Func deserializeFunc = null; + + /// + /// 获取是否得到支持 + /// + public static bool IsSupported { get; private set; } = false; + + /// + /// Json.net + /// + static JsonNet() + { + AppDomain.CurrentDomain.AssemblyLoad += (s, e) => InitJsonNet(e.LoadedAssembly); + InitJsonNet(AppDomain.CurrentDomain.GetAssemblies()); + } + + /// + /// 序列化对象 + /// + /// 对象 + /// + public static string SerializeObject(object obj) + { + return JsonNet.serializeFunc.Invoke(obj); + } + + /// + /// 反序列化为对象 + /// + /// json文本 + /// 对象类型 + /// + public static object DeserializeObject(string json, Type type) + { + return JsonNet.deserializeFunc.Invoke(json, type); + } + + /// + /// 初始化json.net + /// + /// 查找的程序集 + private static void InitJsonNet(params Assembly[] assemblies) + { + if (JsonNet.IsSupported == true) + { + return; + } + + var jsonNetAssembly = assemblies + .FirstOrDefault(item => item.GetName().Name.Equals(jsonNetAssemblyName, StringComparison.OrdinalIgnoreCase)); + + if (jsonNetAssembly == null) + { + return; + } + + var jsonConvertType = jsonNetAssembly.GetType(jsonNetJsonConvertTypeName, false); + if (jsonConvertType == null) + { + return; + } + + serializeFunc = CreateSerializeObjectFunc(jsonConvertType); + deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType); + JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null; + } + + public static bool InitJsonNet(Type jsonConvertType) + { + serializeFunc = CreateSerializeObjectFunc(jsonConvertType); + deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType); + return JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null; + } + + /// + /// 创建SerializeObject方法的委托 + /// + /// JsonConvert类型 + /// + private static Func CreateSerializeObjectFunc(Type classType) + { + var method = classType.GetMethod("SerializeObject", new[] { typeof(object) }); + if (method == null) + { + return null; + } + return (Func)method.CreateDelegate(typeof(Func)); + } + + /// + /// 创建DeserializeObject方法的委托 + /// + /// JsonConvert类型 + /// + private static Func CreateDeserializeObjectFunc(Type classType) + { + var method = classType.GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) }); + if (method == null) + { + return null; + } + return (Func)method.CreateDelegate(typeof(Func)); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs.meta new file mode 100644 index 0000000..82023c7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/Json/JsonNet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c5682694e61a0ec4696fc1fef484a8ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs new file mode 100644 index 0000000..6065721 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs @@ -0,0 +1,524 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Xml.Serialization; + +namespace TouchSocket.Core +{ + /// + /// 高性能序列化器 + /// + //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] + public static partial class SerializeConvert + { +#pragma warning disable SYSLIB0011 // 微软觉得不安全,不推荐使用 + + #region 普通二进制序列化 + + /// + /// 普通二进制序列化对象 + /// + /// 数据对象 + /// + public static byte[] BinarySerialize(object obj) + { + using (MemoryStream serializeStream = new MemoryStream()) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(serializeStream, obj); + return serializeStream.ToArray(); + } + } + + /// + /// 二进制序列化对象至文件 + /// + /// 数据对象 + /// 路径 + public static void BinarySerializeToFile(object obj, string path) + { + using (FileStream serializeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(serializeStream, obj); + serializeStream.Close(); + } + } + + /// + /// 二进制序列化对象 + /// + /// + /// + public static void BinarySerialize(Stream stream, object obj) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(stream, obj); + } + + #endregion 普通二进制序列化 + + #region 普通二进制反序列化 + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data, int offset, int length, SerializationBinder binder = null) + { + using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length)) + { + DeserializeStream.Position = 0; + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return (T)bf.Deserialize(DeserializeStream); + } + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public static object BinaryDeserialize(byte[] data, int offset, int length, SerializationBinder binder = null) + { + using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length)) + { + DeserializeStream.Position = 0; + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return bf.Deserialize(DeserializeStream); + } + } + + /// + /// 从Stream中反序列化 + /// + /// + /// + /// + /// + public static T BinaryDeserialize(Stream stream, SerializationBinder binder = null) + { + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return (T)bf.Deserialize(stream); + } + + /// + /// 将二进制文件数据反序列化为指定类型对象 + /// + /// + /// + /// + public static T BinaryDeserializeFromFile(string path) + { + using (FileStream serializeStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + BinaryFormatter bf = new BinaryFormatter(); + return (T)bf.Deserialize(serializeStream); + } + } + + /// + /// 将二进制数据反序列化为指定类型对象 + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data) + { + return BinaryDeserialize(data, 0, data.Length); + } + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data, SerializationBinder binder = null) + { + return BinaryDeserialize(data, 0, data.Length, binder); + } + + #endregion 普通二进制反序列化 + +#pragma warning restore SYSLIB0011 // 微软觉得不安全,不推荐使用 + + #region Fast二进制序列化 + + /// + /// Fast二进制序列化对象 + /// + /// + /// + /// + public static void FastBinarySerialize(ByteBlock stream, T obj) + { + FastBinaryFormatter.Serialize(stream, obj); + } + + /// + /// Fast二进制序列化对象 + /// + /// + /// + public static byte[] FastBinarySerialize(T obj) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + FastBinarySerialize(byteBlock, obj); + return byteBlock.ToArray(); + } + } + + #endregion Fast二进制序列化 + + #region Fast二进制反序列化 + + /// + /// Fast反序列化 + /// + /// + /// + /// + /// + public static T FastBinaryDeserialize(byte[] data, int offset) + { + return (T)FastBinaryFormatter.Deserialize(data, offset, typeof(T)); + } + + /// + /// Fast反序列化 + /// + /// + /// + /// + /// + public static object FastBinaryDeserialize(byte[] data, int offset, Type type) + { + return FastBinaryFormatter.Deserialize(data, offset, type); + } + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + public static T FastBinaryDeserialize(byte[] data) + { + return FastBinaryDeserialize(data, 0); + } + + #endregion Fast二进制反序列化 + + #region Xml序列化和反序列化 + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// 编码格式 + /// + public static string XmlSerializeToString(object obj, Encoding encoding) + { + return encoding.GetString(XmlSerializeToBytes(obj)); + } + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// + public static string XmlSerializeToString(object obj) + { + return XmlSerializeToString(obj, Encoding.UTF8); + } + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// + public static byte[] XmlSerializeToBytes(object obj) + { + using (MemoryStream fileStream = new MemoryStream()) + { + XmlSerializer xml = new XmlSerializer(obj.GetType()); + xml.Serialize(fileStream, obj); + return fileStream.ToArray(); + } + } + + /// + /// Xml序列化至文件 + /// + /// + /// + public static void XmlSerializeToFile(object obj, string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + XmlSerializer xml = new XmlSerializer(obj.GetType()); + xml.Serialize(fileStream, obj); + fileStream.Close(); + } + } + + /// + /// Xml反序列化 + /// + /// 反序列化类型 + /// 数据 + /// + public static T XmlDeserializeFromBytes(byte[] datas) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + using (Stream xmlstream = new MemoryStream(datas)) + { + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// + /// + /// + public static object XmlDeserializeFromBytes(byte[] datas, Type type) + { + XmlSerializer xmlserializer = new XmlSerializer(type); + using (Stream xmlstream = new MemoryStream(datas)) + { + return xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// 类型 + /// xml字符串 + /// 编码格式 + /// + public static T XmlDeserializeFromString(string xmlString, Encoding encoding) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + using (Stream xmlstream = new MemoryStream(encoding.GetBytes(xmlString))) + { + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// 类型 + /// xml字符串 + /// + public static T XmlDeserializeFromString(string json) + { + return XmlDeserializeFromString(json, Encoding.UTF8); + } + + /// + /// Xml反序列化 + /// + /// 反序列化类型 + /// 文件路径 + /// + public static T XmlDeserializeFromFile(string path) + { + using (Stream xmlstream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + #endregion Xml序列化和反序列化 + + #region Json序列化和反序列化 + + /// + /// 首先使用NewtonsoftJson.默认True。 + /// + /// 当设置True时,json序列化会优先使用NewtonsoftJson(需要将dll加载到程序)。 + /// 当设置为FALSE,或者NewtonsoftJson不可用时,netstandard2.0和net45平台将使用。 + /// 其他平台将使用System.Text.Json。 + /// + /// + public static bool NewtonsoftJsonFirst { get; set; } = true; + + /// + /// 判断是否支持NewtonsoftJson + /// + public static bool NewtonsoftJsonIsSupported => JsonNet.IsSupported; + + /// + /// 主动载入NewtonsoftJson。 + /// + /// 传入命名为JsonConvert的类型 + /// + public static bool LoadNewtonsoftJson(Type jsonConvertType) + { + return JsonNet.InitJsonNet(jsonConvertType); + } + + /// + /// 转换为Json + /// + /// + /// + public static string ToJson(this object item) + { + if (NewtonsoftJsonFirst && JsonNet.IsSupported) + { + return JsonNet.SerializeObject(item); + } + +#if NETCOREAPP3_1_OR_GREATER + return System.Text.Json.JsonSerializer.Serialize(item); +#else + return JsonFastConverter.JsonTo(item); +#endif + } + + /// + /// 从字符串到json + /// + /// + /// + /// + public static object FromJson(this string json, Type type) + { + if (NewtonsoftJsonFirst && JsonNet.IsSupported) + { + return JsonNet.DeserializeObject(json, type); + } + +#if NETCOREAPP3_1_OR_GREATER + return System.Text.Json.JsonSerializer.Deserialize(json,type); +#else + return JsonFastConverter.JsonFrom(json, type); +#endif + } + + /// + /// 从字符串到json + /// + /// + /// + /// + public static T FromJson(this string json) + { + return (T)FromJson(json, typeof(T)); + } + + /// + /// Json序列化数据对象 + /// + /// 数据对象 + /// + public static byte[] JsonSerializeToBytes(object obj) + { + return ToJson(obj).ToUTF8Bytes(); + } + + /// + /// Json序列化至文件 + /// + /// + /// + public static void JsonSerializeToFile(object obj, string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + var date = JsonSerializeToBytes(obj); + fileStream.Write(date, 0, date.Length); + fileStream.Close(); + } + } + + /// + /// Json反序列化 + /// + /// 反序列化类型 + /// 数据 + /// + public static T JsonDeserializeFromBytes(byte[] datas) + { + return (T)JsonDeserializeFromBytes(datas, typeof(T)); + } + + /// + /// Xml反序列化 + /// + /// + /// + /// + public static object JsonDeserializeFromBytes(byte[] datas, Type type) + { + return FromJson(Encoding.UTF8.GetString(datas), type); + } + + /// + /// Json反序列化 + /// + /// 类型 + /// json字符串 + /// + public static T JsonDeserializeFromString(string json) + { + return FromJson(json); + } + + /// + /// Json反序列化 + /// + /// 反序列化类型 + /// 文件路径 + /// + public static T JsonDeserializeFromFile(string path) + { + return JsonDeserializeFromString(File.ReadAllText(path)); + } + + #endregion Json序列化和反序列化 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs.meta new file mode 100644 index 0000000..442a08c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Serialization/SerializeConvert.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8755309666c9c2a438f50ce7e6fa152b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt new file mode 100644 index 0000000..8c0373c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt @@ -0,0 +1,10 @@ +该程序代码由三大部分组成,网络来源、开源程序集以及自编代码。若汝棋茗仅享有自编代码版权,且只为自编代码授权。 +其中代码版权说明由于是工具生成,所以会对非自编代码也标注,但是我们会在类注释中说明, +或设置XREF命名空间(XREF命名空间下的所有代码均来自开源社区)表示,所以请读者悉知。 + +例如: +1、SnowflakeIDGenerator类代码,来源于网络,所以已在类注释中说明。 + + +感谢!! +感谢所有第三方代码的开源贡献。 diff --git a/HandDriver/package.json.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt.meta similarity index 75% rename from HandDriver/package.json.meta rename to Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt.meta index 0d18ee9..ed60bfc 100644 --- a/HandDriver/package.json.meta +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/代码说明.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 074f31793dddd1042887e51c6005051c +guid: fee13616f50ace540ae1818593fcaf39 TextScriptImporter: externalObjects: {} userData: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http.meta new file mode 100644 index 0000000..e18c5b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca68c5f4685b98d4fade12481ec60d25 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common.meta new file mode 100644 index 0000000..218f819 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 223b26d1fa126bd4d9bf69dbaeff0954 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs new file mode 100644 index 0000000..020d32a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs @@ -0,0 +1,444 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Web; +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// 静态文件缓存池 + /// + public class FileCachePool : DisposableObject + { + /// + /// 添加委托 + /// + /// + /// + /// + /// + /// + public delegate bool InsertHandler(FileCachePool cache, string key, byte[] value, TimeSpan timeout); + + #region Cache items access + + /// + /// Is the file cache empty? + /// + public bool Empty => entriesByKey.Count == 0; + + /// + /// Get the file cache size + /// + public int Size => entriesByKey.Count; + + /// + /// Add a new cache value with the given timeout into the file cache + /// + /// Key to add + /// Value to add + /// Cache timeout (default is 0 - no timeout) + /// 'true' if the cache value was added, 'false' if the given key was not added + public bool Add(string key, byte[] value, TimeSpan timeout = new TimeSpan()) + { + using (new WriteLock(lockEx)) + { + // Try to find and remove the previous key + entriesByKey.Remove(key); + + // Update the cache entry + entriesByKey.Add(key, new MemCacheEntry(value, timeout)); + + return true; + } + } + + /// + /// Try to find the cache value by the given key + /// + /// Key to find + /// + /// 'true' and cache value if the cache value was found, 'false' if the given key was not found + public bool Find(string key, out byte[] data) + { + using (new ReadLock(lockEx)) + { + // Try to find the given key + if (!entriesByKey.TryGetValue(key, out var cacheValue)) + { + data = null; + return false; + } + data = cacheValue.Value; + return true; + } + } + + /// + /// Remove the cache value with the given key from the file cache + /// + /// Key to remove + /// 'true' if the cache value was removed, 'false' if the given key was not found + public bool Remove(string key) + { + using (new WriteLock(lockEx)) + { + return entriesByKey.Remove(key); + } + } + + #endregion Cache items access + + #region Cache management methods + + /// + /// Insert a new cache path with the given timeout into the file cache + /// + /// Path to insert + /// Cache prefix (default is "/") + /// Cache filter (default is "*.*") + /// Cache timeout (default is 0 - no timeout) + /// Cache insert handler (default is 'return cache.Add(key, value, timeout)') + /// 'true' if the cache path was setup, 'false' if failed to setup the cache path + public bool InsertPath(string path, string prefix = "/", string filter = "*.*", TimeSpan timeout = new TimeSpan(), InsertHandler handler = null) + { + handler ??= (FileCachePool cache, string key, byte[] value, TimeSpan timespan) => cache.Add(key, value, timespan); + + // Try to find and remove the previous path + RemovePathInternal(path); + + using (new WriteLock(lockEx)) + { + // Add the given path to the cache + pathsByKey.Add(path, new FileCacheEntry(this, prefix, path, filter, handler, timeout)); + // Create entries by path map + entriesByPath[path] = new HashSet(); + } + + // Insert the cache path + if (!InsertPathInternal(path, path, prefix, timeout, handler)) + return false; + + return true; + } + + /// + /// Try to find the cache path + /// + /// Path to find + /// 'true' if the cache path was found, 'false' if the given path was not found + public bool FindPath(string path) + { + using (new ReadLock(lockEx)) + { + // Try to find the given key + return pathsByKey.ContainsKey(path); + } + } + + /// + /// Remove the cache path from the file cache + /// + /// Path to remove + /// 'true' if the cache path was removed, 'false' if the given path was not found + public bool RemovePath(string path) + { + return RemovePathInternal(path); + } + + /// + /// Clear the memory cache + /// + public void Clear() + { + using (new WriteLock(lockEx)) + { + // Stop all file system watchers + foreach (var fileCacheEntry in pathsByKey) + fileCacheEntry.Value.StopWatcher(); + + // Clear all cache entries + entriesByKey.Clear(); + entriesByPath.Clear(); + pathsByKey.Clear(); + } + } + + #endregion Cache management methods + + #region Cache implementation + + private readonly ReaderWriterLockSlim lockEx = new ReaderWriterLockSlim(); + private readonly Dictionary entriesByKey = new Dictionary(); + private readonly Dictionary> entriesByPath = new Dictionary>(); + private readonly Dictionary pathsByKey = new Dictionary(); + + private class MemCacheEntry + { + private readonly byte[] _value; + private readonly TimeSpan _timespan; + + public byte[] Value => _value; + public TimeSpan Timespan => _timespan; + + public MemCacheEntry(byte[] value, TimeSpan timespan = new TimeSpan()) + { + _value = value; + _timespan = timespan; + } + + public MemCacheEntry(string value, TimeSpan timespan = new TimeSpan()) + { + _value = Encoding.UTF8.GetBytes(value); + _timespan = timespan; + } + }; + + private class FileCacheEntry + { + private readonly string _prefix; + private readonly string _path; + private readonly InsertHandler _handler; + private readonly TimeSpan _timespan; + private readonly FileSystemWatcher _watcher; + + public FileCacheEntry(FileCachePool cache, string prefix, string path, string filter, InsertHandler handler, TimeSpan timespan) + { + _prefix = prefix; + _path = path; + _handler = handler; + _timespan = timespan; + _watcher = new FileSystemWatcher(); + + // Start the filesystem watcher + StartWatcher(cache, path, filter); + } + + private void StartWatcher(FileCachePool cache, string path, string filter) + { + FileCacheEntry entry = this; + + // Initialize a new filesystem watcher + _watcher.Created += (sender, e) => OnCreated(sender, e, cache, entry); + _watcher.Changed += (sender, e) => OnChanged(sender, e, cache, entry); + _watcher.Deleted += (sender, e) => OnDeleted(sender, e, cache, entry); + _watcher.Renamed += (sender, e) => OnRenamed(sender, e, cache, entry); + _watcher.Path = path; + _watcher.IncludeSubdirectories = true; + _watcher.Filter = filter; + _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite; + _watcher.EnableRaisingEvents = true; + } + + public void StopWatcher() + { + _watcher.Dispose(); + } + + private static bool IsDirectory(string path) + { + try + { + // Skip directory updates + if (File.GetAttributes(path).HasFlag(FileAttributes.Directory)) + return true; + } + catch (Exception) { } + + return false; + } + + private static void OnCreated(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + // Skip missing files + if (!File.Exists(file)) + return; + // Skip directory updates + if (IsDirectory(file)) + return; + + cache.InsertFileInternal(entry._path, file, key, entry._timespan, entry._handler); + } + + private static void OnChanged(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + if (e.ChangeType != WatcherChangeTypes.Changed) + return; + + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + // Skip missing files + if (!File.Exists(file)) + return; + // Skip directory updates + if (IsDirectory(file)) + return; + + cache.InsertFileInternal(entry._path, file, key, entry._timespan, entry._handler); + } + + private static void OnDeleted(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + cache.RemoveFileInternal(entry._path, key); + } + + private static void OnRenamed(object sender, RenamedEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var oldKey = e.OldFullPath.Replace(entry._path, entry._prefix); + var oldFile = e.OldFullPath; + var newKey = e.FullPath.Replace(entry._path, entry._prefix); + var newFile = e.FullPath; + + // Skip missing files + if (!File.Exists(newFile)) + return; + // Skip directory updates + if (IsDirectory(newFile)) + return; + + cache.RemoveFileInternal(entry._path, oldKey); + cache.InsertFileInternal(entry._path, newFile, newKey, entry._timespan, entry._handler); + } + }; + + private bool InsertFileInternal(string path, string file, string key, TimeSpan timeout, InsertHandler handler) + { + try + { + key = key.Replace('\\', '/'); + file = file.Replace('\\', '/'); + + // Load the cache file content + var content = File.ReadAllBytes(file); + if (!handler(this, key, content, timeout)) + return false; + + using (new WriteLock(lockEx)) + { + // Update entries by path map + entriesByPath[path].Add(key); + } + + return true; + } + catch (Exception) { return false; } + } + + private bool RemoveFileInternal(string path, string key) + { + try + { + key = key.Replace('\\', '/'); + + using (new WriteLock(lockEx)) + { + // Update entries by path map + entriesByPath[path].Remove(key); + } + + return Remove(key); + } + catch (Exception) { return false; } + } + + private bool InsertPathInternal(string root, string path, string prefix, TimeSpan timeout, InsertHandler handler) + { + try + { + string keyPrefix = (string.IsNullOrEmpty(prefix) || (prefix == "/")) ? "/" : (prefix + "/"); + + // Iterate through all directory entries + foreach (var item in Directory.GetDirectories(path)) + { + string key = keyPrefix /*+ HttpUtility.UrlDecode(Path.GetFileName(item))*/; + + // Recursively insert sub-directory + if (!InsertPathInternal(root, item, key, timeout, handler)) + return false; + } + + foreach (var item in Directory.GetFiles(path)) + { + string key = keyPrefix /*+ HttpUtility.UrlDecode(Path.GetFileName(item))*/; + + // Insert file into the cache + if (!InsertFileInternal(root, item, key, timeout, handler)) + return false; + } + + return true; + } + catch (Exception) { return false; } + } + + private bool RemovePathInternal(string path) + { + using (new WriteLock(lockEx)) + { + // Try to find the given path + if (!pathsByKey.TryGetValue(path, out var cacheValue)) + return false; + + // Stop the file system watcher + cacheValue.StopWatcher(); + + // Remove path entries + foreach (var entryKey in entriesByPath[path]) + entriesByKey.Remove(entryKey); + entriesByPath.Remove(path); + + // Remove cache path + pathsByKey.Remove(path); + + return true; + } + } + + #endregion Cache implementation + + #region IDisposable implementation + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + Clear(); + base.Dispose(disposing); + } + + /// + /// 析构函数 + /// + ~FileCachePool() + { + // Simply call Dispose(false). + Dispose(false); + } + + #endregion IDisposable implementation + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs.meta new file mode 100644 index 0000000..9a64e13 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/FileCachePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b65fbcba5a72b04cb211a7f982ab98f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs new file mode 100644 index 0000000..454346b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs @@ -0,0 +1,279 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http基础头部 + /// + public abstract class HttpBase : BlockReader, IRequestInfo + { + /// + /// 服务器版本 + /// + public static readonly string ServerVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + /// + /// 内容长度 + /// + protected long m_contentLength; + + private static readonly byte[] m_rnrnCode = Encoding.UTF8.GetBytes("\r\n\r\n"); + + private IgnoreCaseNameValueCollection m_headers; + + /// + /// 构造函数 + /// + public HttpBase() + { + ReadTimeout = 1000 * 30; + } + + /// + /// 能否写入。 + /// + public abstract bool CanWrite { get; } + + /// + /// 客户端 + /// + public abstract ITcpClientBase Client { get; } + + /// + /// 内容填充完成 + /// + public bool? ContentComplated { get; protected set; } = null; + + /// + /// int类型,内容长度 + /// + public int ContentLen + { + get => (int)m_contentLength; + set => m_contentLength = value; + } + + /// + /// 内容长度 + /// + public long ContentLength + { + get => m_contentLength; + set => m_contentLength = value; + } + + /// + /// 内容类型 + /// + public string ContentType { get; set; } + + /// + /// 传递标识 + /// + public object Flag { get; set; } + + /// + /// 请求头集合 + /// + public IgnoreCaseNameValueCollection Headers + { + get + { + m_headers ??= new IgnoreCaseNameValueCollection(); + return m_headers; + } + } + + /// + /// 协议名称,默认HTTP + /// + public string Protocols { get; set; } = "HTTP"; + + /// + /// HTTP协议版本,默认1.1 + /// + public string ProtocolVersion { get; set; } = "1.1"; + + /// + /// 请求行 + /// + public string RequestLine { get; private set; } + + /// + /// 获取头值 + /// + /// + /// + public string GetHeader(string fieldName) + { + return GetHeaderByKey(fieldName); + } + + /// + /// 获取头集合的值 + /// + /// + /// + public string GetHeader(HttpHeaders header) + { + var fieldName = header.GetDescription(); + if (fieldName == null) return null; + return Headers.Get(fieldName); + } + + /// + /// + /// + /// + /// + /// + public bool ParsingHeader(ByteBlock byteBlock, int length) + { + int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, length, m_rnrnCode); + if (index > 0) + { + int headerLength = index - byteBlock.Pos; + ReadHeaders(byteBlock.Buffer, byteBlock.Pos, headerLength); + byteBlock.Pos += headerLength; + return true; + } + else + { + return false; + } + } + + /// + /// 从Request中持续读取数据。 + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + return base.Read(buffer, offset, count); + } + + /// + /// 从内存中读取 + /// + /// + /// + /// + public void ReadHeaders(byte[] buffer, int offset, int length) + { + string data = Encoding.UTF8.GetString(buffer, offset, length); + string[] rows = Regex.Split(data, "\r\n"); + + //Request URL & Method & Version + RequestLine = rows[0]; + + //Request Headers + GetRequestHeaders(rows); + long.TryParse(GetHeader(HttpHeaders.ContentLength), out m_contentLength); + LoadHeaderProterties(); + } + + /// + /// 设置一次性内容 + /// + /// + /// + public abstract void SetContent(byte[] content); + + /// + /// 设置请求头 + /// + /// + /// + public HttpBase SetHeaderByKey(string fieldName, string value) + { + if (string.IsNullOrEmpty(fieldName)) return this; + Headers.Add(fieldName, value); + return this; + } + + /// + /// 获取一次性内容。 + /// + /// + public abstract bool TryGetContent(out byte[] content); + + /// + /// 持续写入内容。 + /// + /// + /// + /// + public abstract void WriteContent(byte[] buffer, int offset, int count); + + internal bool InternalInput(byte[] buffer, int offset, int length) + { + return Input(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue && CanRead) + { + TryGetContent(out _); + } + + base.Dispose(disposing); + } + + /// + /// 读取信息 + /// + protected abstract void LoadHeaderProterties(); + + private string GetHeaderByKey(string fieldName) + { + if (string.IsNullOrEmpty(fieldName)) return null; + return Headers.Get(fieldName); + } + + private void GetRequestHeaders(IEnumerable rows) + { + if (rows == null || rows.Count() <= 0) + { + return; + } + + foreach (var item in rows) + { + string[] kv = item.SplitFirst(':'); + if (kv.Length == 2) + { + string key = kv[0].ToLower(); + Headers.Add(key, kv[1]); + } + } + + ContentType = GetHeader(HttpHeaders.ContentType); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs.meta new file mode 100644 index 0000000..09fd544 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21998373b685ce542aeb39c92aaf0fb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs new file mode 100644 index 0000000..68bb4d0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Http +{ + /// + /// Http上下文 + /// + public class HttpContext + { + private HttpResponse m_response; + + /// + /// 构造函数 + /// + /// + public HttpContext(HttpRequest request) + { + Request = request ?? throw new ArgumentNullException(nameof(request)); + } + + /// + /// 构造函数 + /// + /// + /// + public HttpContext(HttpRequest request, HttpResponse response) + { + Request = request ?? throw new ArgumentNullException(nameof(request)); + m_response = response ?? throw new ArgumentNullException(nameof(response)); + } + + /// + /// Http请求 + /// + public HttpRequest Request { get; } + + /// + /// Http响应 + /// + public HttpResponse Response + { + get + { + lock (this) + { + if (m_response == null) + { + m_response = new HttpResponse(Request.Client, true); + } + return m_response; + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs.meta new file mode 100644 index 0000000..d1c6952 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5ea4b7b44df9614e8ba96f9904ea11a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs new file mode 100644 index 0000000..9b27142 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http代理 + /// + public class HttpProxy + { + /// + /// 不带基本验证的代理 + /// + /// + public HttpProxy(IPHost host) + { + Host = host; + } + + /// + /// 带基本验证的代理 + /// + /// + /// + /// + public HttpProxy(IPHost host, string userName, string passWord) + { + Host = host; + Credential = new NetworkCredential(userName, passWord, $"{host.IP}:{host.Port}"); + } + + /// + /// 验证代理 + /// + public NetworkCredential Credential { get; set; } + + /// + /// 代理的地址 + /// + public IPHost Host { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs.meta new file mode 100644 index 0000000..90ccfcb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpProxy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9090b888c8f7d834596380ae9586a1d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs new file mode 100644 index 0000000..fa9e548 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs @@ -0,0 +1,139 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Http +{ + /// + /// Range: bytes=0-499 表示第 0-499 字节范围的内容 + /// Range: bytes=500-999 表示第 500-999 字节范围的内容 + /// Range: bytes=-500 表示最后 500 字节的内容 + /// Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容 + /// Range: bytes=0-0,-1 表示第一个和最后一个字节 + /// Range: bytes=500-600,601-999 同时指定几个范围 + /// + public class HttpRange + { + /// + /// 转换获取的集合 + /// + /// + /// + /// + public static HttpRange[] GetRanges(string rangeStr, long size) + { + string[] ranges = rangeStr.Split('='); + if (ranges.Length != 2) + { + return new HttpRange[0]; + } + rangeStr = ranges[1]; + if (string.IsNullOrEmpty(rangeStr)) + { + return new HttpRange[0]; + } + ranges = rangeStr.Split(','); + List httpRanges = new List(); + foreach (var range in ranges) + { + HttpRange httpRange = new HttpRange(); + ranges = range.Split('-'); + if (ranges.Length == 2) + { + if (range.StartsWith("-")) + { + httpRange.Length = Convert.ToInt64(ranges[1]); + httpRange.Start = size - httpRange.Length; + } + else if (range.EndsWith("-")) + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = size - httpRange.Start; + } + else + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = Convert.ToInt64(ranges[1]) - httpRange.Start + 1; + } + } + else + { + continue; + } + httpRanges.Add(httpRange); + } + return httpRanges.ToArray(); + } + + /// + /// 转换获取的集合 + /// + /// + /// + /// + public static HttpRange GetRange(string rangeStr, long size) + { + string[] ranges = rangeStr.Split('='); + if (ranges.Length != 2) + { + return null; + } + rangeStr = ranges[1]; + if (string.IsNullOrEmpty(rangeStr)) + { + return null; + } + ranges = rangeStr.Split(','); + foreach (var range in ranges) + { + HttpRange httpRange = new HttpRange(); + ranges = range.Split('-'); + if (ranges.Length == 2) + { + if (range.StartsWith("-")) + { + httpRange.Length = Convert.ToInt64(ranges[1]); + httpRange.Start = size - httpRange.Length; + } + else if (range.EndsWith("-")) + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = size - httpRange.Start; + } + else + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = Convert.ToInt64(ranges[1]) - httpRange.Start + 1; + } + } + else + { + continue; + } + return httpRange; + } + return null; + } + + /// + /// 起始位置 + /// + public long Start { get; set; } = -1; + + /// + /// 长度 + /// + public long Length { get; set; } = -1; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs.meta new file mode 100644 index 0000000..d9a3105 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRange.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: feb60cb54ffccf0469f49e399863eaf7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs new file mode 100644 index 0000000..4787126 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs @@ -0,0 +1,455 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HTTP请求定义 + /// + public class HttpRequest : HttpBase + { + private bool m_canRead; + private ITcpClientBase m_client; + private byte[] m_content; + private NameValueCollection m_forms; + private NameValueCollection m_params; + private NameValueCollection m_query; + private string m_relativeURL; + private bool m_sentHeader; + private int m_sentLength; + private string m_uRL; + + /// + /// 构造函数 + /// + /// + /// + public HttpRequest(ITcpClientBase client, bool isServer = false) + { + m_client = client; + if (isServer) + { + m_canRead = true; + CanWrite = false; + } + else + { + m_canRead = false; + CanWrite = true; + } + } + + /// + /// 构造函数 + /// + public HttpRequest() + { + m_canRead = false; + CanWrite = false; + } + + /// + /// + /// + public override bool CanRead => m_canRead; + + /// + /// + /// + public override bool CanWrite { get; } + + /// + /// + /// + public override ITcpClientBase Client => m_client; + + /// + /// 表单数据 + /// + public NameValueCollection Forms + { + get + { + if (ContentType == @"application/x-www-form-urlencoded") + { + m_forms ??= GetParameters(this.GetBody()); + return m_forms; + } + + return m_forms ??= new NameValueCollection(); + } + } + + /// + /// 获取时候保持连接 + /// + public bool KeepAlive + { + get + { + if (ProtocolVersion == "1.0") + { + return false; + } + else + { + if (GetHeader(HttpHeaders.Connection) == "keep-alive") + { + return true; + } + else + { + return false; + } + } + } + } + + /// + /// HTTP请求方式。 + /// + public string Method { get; set; } + + /// + /// Body参数 + /// + public NameValueCollection Params + { + get + { + m_params ??= new NameValueCollection(); + return m_params; + } + } + + /// + /// url参数 + /// + public NameValueCollection Query + { + get + { + m_query ??= new NameValueCollection(); + return m_query; + } + } + + /// + /// 相对路径(不含参数) + /// + public string RelativeURL => m_relativeURL; + + /// + /// Url全地址,包含参数 + /// + public string URL => m_uRL; + + /// + /// 构建响应数据。 + /// 当数据较大时,不建议这样操作,可直接 + /// + /// + public void Build(ByteBlock byteBlock) + { + BuildHeader(byteBlock); + BuildContent(byteBlock); + } + + /// + /// 构建数据为字节数组。 + /// + /// + public byte[] BuildAsBytes() + { + using ByteBlock byteBlock = new ByteBlock(); + Build(byteBlock); + return byteBlock.ToArray(); + } + + /// + /// 设置内容 + /// + /// + public override void SetContent(byte[] content) + { + m_content = content; + ContentLength = content.Length; + ContentComplated = true; + } + + /// + /// 设置Url,必须以“/”开头,可带参数 + /// + /// + /// + /// + public HttpRequest SetUrl(string url, bool justValue = false) + { + if (justValue || url.StartsWith("/")) + { + m_uRL = url; + } + else + { + m_uRL = "/" + url; + } + ParseUrl(); + return this; + } + + /// + /// 输出 + /// + public override string ToString() + { + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + return byteBlock.ToString(); + } + } + + /// + /// + /// + /// + public override bool TryGetContent(out byte[] content) + { + if (!ContentComplated.HasValue) + { + if (m_contentLength == 0) + { + m_content = new byte[0]; + content = m_content; + ContentComplated = true; + return true; + } + try + { + using MemoryStream block1 = new MemoryStream(); + using ByteBlock block2 = new ByteBlock(); + byte[] buffer = block2.Buffer; + while (true) + { + int r = Read(buffer, 0, buffer.Length); + if (r == 0) + { + break; + } + block1.Write(buffer, 0, r); + } + ContentComplated = true; + m_content = block1.ToArray(); + content = m_content; + return true; + } + catch + { + ContentComplated = false; + content = null; + return false; + } + finally + { + m_canRead = false; + } + } + else if (ContentComplated == true) + { + content = m_content; + return true; + } + else + { + content = null; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public override void WriteContent(byte[] buffer, int offset, int count) + { + if (!CanWrite) + { + throw new NotSupportedException("该对象不支持持续写入内容。"); + } + if (!m_sentHeader) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + BuildHeader(byteBlock); + m_client.DefaultSend(byteBlock); + } + m_sentHeader = true; + } + if (m_sentLength + count <= m_contentLength) + { + m_client.DefaultSend(buffer, offset, count); + m_sentLength += count; + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_client = null; + base.Dispose(disposing); + } + + /// + /// 从内存中读取 + /// + protected override void LoadHeaderProterties() + { + var first = Regex.Split(RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray(); + if (first.Length > 0) Method = first[0].Trim().ToUpper(); + if (first.Length > 1) + { + SetUrl(Uri.UnescapeDataString(first[1])); + } + if (first.Length > 2) + { + string[] ps = first[2].Split('/'); + if (ps.Length == 2) + { + Protocols = ps[0]; + ProtocolVersion = ps[1]; + } + } + } + + private void BuildContent(ByteBlock byteBlock) + { + if (ContentLength > 0) + { + byteBlock.Write(m_content); + } + } + + /// + /// 构建响应头部 + /// + /// + private void BuildHeader(ByteBlock byteBlock) + { + StringBuilder stringBuilder = new StringBuilder(); + + string url = null; + if (!string.IsNullOrEmpty(m_relativeURL)) + { + if (m_query == null) + { + url = m_relativeURL; + } + else + { + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.Append(m_relativeURL); + urlBuilder.Append("?"); + int i = 0; + foreach (var item in m_query.AllKeys) + { + urlBuilder.Append($"{item}={m_query[item]}"); + if (++i < m_query.Count) + { + urlBuilder.Append("&"); + } + } + url = urlBuilder.ToString(); + } + } + + if (string.IsNullOrEmpty(url)) + { + stringBuilder.Append($"{Method} / HTTP/{ProtocolVersion}\r\n"); + } + else + { + stringBuilder.Append($"{Method} {url} HTTP/{ProtocolVersion}\r\n"); + } + if (ContentLength > 0) + { + this.SetHeader(HttpHeaders.ContentLength, ContentLength.ToString()); + } + foreach (var headerkey in Headers.AllKeys) + { + stringBuilder.Append($"{headerkey}: "); + stringBuilder.Append(Headers[headerkey] + "\r\n"); + } + + stringBuilder.Append("\r\n"); + byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString())); + } + + private NameValueCollection GetParameters(string row) + { + if (string.IsNullOrEmpty(row)) + { + return null; + } + string[] kvs = row.Split('&'); + if (kvs == null || kvs.Count() == 0) + { + return null; + } + + NameValueCollection pairs = new NameValueCollection(); + foreach (var item in kvs) + { + string[] kv = item.SplitFirst('='); + if (kv.Length == 2) + { + pairs.Add(kv[0], kv[1]); + } + } + + return pairs; + } + + private void ParseUrl() + { + if (m_uRL.Contains("?")) + { + string[] urls = m_uRL.Split('?'); + if (urls.Length > 0) + { + m_relativeURL = urls[0]; + } + if (urls.Length > 1) + { + m_query = GetParameters(urls[1]); + } + } + else + { + m_relativeURL = m_uRL; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs.meta new file mode 100644 index 0000000..6e2564d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05c878494cc8f494bbb21926239dde97 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs new file mode 100644 index 0000000..40d4986 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs @@ -0,0 +1,405 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http响应 + /// + public class HttpResponse : HttpBase + { + private bool m_canRead; + private bool m_canWrite; + private ITcpClientBase m_client; + private byte[] m_content; + private bool m_responsed; + private bool m_sentHeader; + private long m_sentLength; + + /// + /// 构造函数 + /// + /// + /// + public HttpResponse(ITcpClientBase client, bool isServer = true) + { + m_client = client; + if (isServer) + { + m_canRead = false; + m_canWrite = true; + } + else + { + m_canRead = true; + m_canWrite = false; + } + } + + /// + /// 构造函数 + /// + public HttpResponse() + { + m_canRead = false; + m_canWrite = false; + } + + /// + /// + /// + public override bool CanRead => m_canRead; + + /// + /// + /// + public override bool CanWrite => m_canWrite; + + /// + /// + /// + public override ITcpClientBase Client => m_client; + + /// + /// 关闭会话请求 + /// + public bool CloseConnection + { + get + { + return GetHeader(HttpHeaders.Connection).Equals("close", StringComparison.CurrentCultureIgnoreCase); + } + } + + /// + /// 是否分块 + /// + public bool IsChunk { get; set; } + + /// + /// 是否代理权限验证。 + /// + public bool IsProxyAuthenticationRequired + { + get + { + return StatusCode == "407"; + } + } + + /// + /// 是否重定向 + /// + public bool IsRedirect + { + get + { + return StatusCode == "301" || StatusCode == "302"; + } + } + + /// + /// 是否已经响应数据。 + /// + public bool Responsed => m_responsed; + + /// + /// 状态码,默认200 + /// + public string StatusCode { get; set; } = "200"; + + /// + /// 状态消息,默认Success + /// + public string StatusMessage { get; set; } = "Success"; + + /// + /// 构建数据并回应。 + /// 该方法仅在具有Client实例时有效。 + /// + public void Answer() + { + if (m_responsed) + { + return; + } + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + if (m_client.CanSend) + { + m_client.DefaultSend(byteBlock); + } + m_responsed = true; + } + } + + /// + /// 构建响应数据。 + /// 当数据较大时,不建议这样操作,可直接 + /// + /// + /// + public void Build(ByteBlock byteBlock, bool responsed = true) + { + if (m_responsed) + { + throw new Exception("该对象已被响应。"); + } + + BuildHeader(byteBlock); + BuildContent(byteBlock); + m_responsed = responsed; + } + + /// + /// 构建数据为字节数组。 + /// + /// + public byte[] BuildAsBytes() + { + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + return byteBlock.ToArray(); + } + } + + /// + /// 当传输模式是Chunk时,用于结束传输。 + /// + public void Complete() + { + m_canWrite = false; + if (IsChunk) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.Write(Encoding.UTF8.GetBytes($"{0:X}\r\n")); + byteBlock.Write(Encoding.UTF8.GetBytes("\r\n")); + m_client.DefaultSend(byteBlock); + m_responsed = true; + } + } + } + + /// + /// + /// + /// + public override void SetContent(byte[] content) + { + m_content = content; + ContentLength = content.Length; + ContentComplated = true; + } + + /// + /// + /// + /// + public override bool TryGetContent(out byte[] content) + { + if (!ContentComplated.HasValue) + { + if (!IsChunk && m_contentLength == 0) + { + m_content = new byte[0]; + content = m_content; + return true; + } + + try + { + using (ByteBlock block1 = new ByteBlock(1024 * 1024)) + { + using (ByteBlock block2 = new ByteBlock()) + { + byte[] buffer = block2.Buffer; + while (true) + { + int r = Read(buffer, 0, buffer.Length); + if (r == 0) + { + break; + } + block1.Write(buffer, 0, r); + } + ContentComplated = true; + m_content = block1.ToArray(); + content = m_content; + return true; + } + } + } + catch + { + ContentComplated = false; + content = null; + return false; + } + finally + { + m_canRead = false; + } + } + else if (ContentComplated == true) + { + content = m_content; + return true; + } + else + { + content = null; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public override void WriteContent(byte[] buffer, int offset, int count) + { + if (m_responsed) + { + throw new Exception("该对象已被响应。"); + } + + if (!CanWrite) + { + throw new NotSupportedException("该对象不支持持续写入内容。"); + } + + if (!m_sentHeader) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + BuildHeader(byteBlock); + m_client.DefaultSend(byteBlock); + } + m_sentHeader = true; + } + if (IsChunk) + { + using (ByteBlock byteBlock = new ByteBlock(count + 1024)) + { + byteBlock.Write(Encoding.UTF8.GetBytes($"{count.ToString("X")}\r\n")); + byteBlock.Write(buffer, offset, count); + byteBlock.Write(Encoding.UTF8.GetBytes("\r\n")); + m_client.DefaultSend(byteBlock); + m_sentLength += count; + } + } + else + { + if (m_sentLength + count <= m_contentLength) + { + m_client.DefaultSend(buffer, offset, count); + m_sentLength += count; + if (m_sentLength == ContentLength) + { + m_canWrite = false; + m_responsed = true; + } + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_client = null; + base.Dispose(disposing); + } + + /// + /// 读取数据 + /// + protected override void LoadHeaderProterties() + { + var first = Regex.Split(RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray(); + if (first.Length > 0) + { + string[] ps = first[0].Split('/'); + if (ps.Length == 2) + { + Protocols = ps[0]; + ProtocolVersion = ps[1]; + } + } + if (first.Length > 1) + { + StatusCode = first[1]; + } + string msg = string.Empty; + for (int i = 2; i < first.Length; i++) + { + msg += first[i] + " "; + } + StatusMessage = msg; + + string transferEncoding = GetHeader(HttpHeaders.TransferEncoding); + if ("chunked".Equals(transferEncoding, StringComparison.OrdinalIgnoreCase)) + { + IsChunk = true; + } + } + + private void BuildContent(ByteBlock byteBlock) + { + if (ContentLength > 0) + { + byteBlock.Write(m_content); + } + } + + /// + /// 构建响应头部 + /// + /// + private void BuildHeader(ByteBlock byteBlock) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"HTTP/{ProtocolVersion} {StatusCode} {StatusMessage}\r\n"); + + if (ContentLength > 0) + { + this.SetHeader(HttpHeaders.ContentLength, ContentLength.ToString()); + } + if (IsChunk) + { + this.SetHeader(HttpHeaders.TransferEncoding, "chunked"); + } + foreach (var headerkey in Headers.AllKeys) + { + stringBuilder.Append($"{headerkey}: "); + stringBuilder.Append(Headers[headerkey] + "\r\n"); + } + + stringBuilder.Append("\r\n"); + byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString())); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs.meta new file mode 100644 index 0000000..7014222 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45486df1642bd034f8dfafb7278bd227 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs new file mode 100644 index 0000000..180503b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Http +{ + /// + /// Http工具 + /// + public static class HttpTools + { + /// + /// 从扩展名获取ContentType + /// + /// + /// + public static string GetContentTypeFromExtension(string extension) + { + switch (extension.ToLower()) + { + case ".html": + return "text/html"; + + case ".css": + return "text/css"; + + case ".js": + return "text/javascript"; + + case ".xml": + return "text/xml"; + + case ".gzip": + return "application/gzip"; + + case ".json": + return "application/json"; + + case ".map": + return "application/json"; + + case ".pdf": + return "application/pdf"; + + case ".zip": + return "application/zip"; + + case ".mp3": + return "audio/mpeg"; + + case ".jpg": + return "image/jpeg"; + + case ".gif": + return "image/gif"; + + case ".png": + return "image/png"; + + case ".svg": + return "image/svg+xml"; + + case ".mp4": + return "video/mp4"; + + case ".atom": + return "application/atom+xml"; + + case ".fastsoap": + return "application/fastsoap"; + + case ".ps": + return "application/postscript"; + + case ".soap": + return "application/soap+xml"; + + case ".sql": + return "application/sql"; + + case ".xslt": + return "application/xslt+xml"; + + case ".zlib": + return "application/zlib"; + + case ".aac": + return "audio/aac"; + + case ".ac3": + return "audio/ac3"; + + case ".ogg": + return "audio/ogg"; + + case ".ttf": + return "font/ttf"; + + case ".bmp": + return "image/bmp"; + + case ".jpm": + return "image/jpm"; + + case ".jpx": + return "image/jpx"; + + case ".jrx": + return "image/jrx"; + + case ".tiff": + return "image/tiff"; + + case ".emf": + return "image/emf"; + + case ".wmf": + return "image/wmf"; + + case ".http": + return "message/http"; + + case ".s-http": + return "message/s-http"; + + case ".mesh": + return "model/mesh"; + + case ".vrml": + return "model/vrml"; + + case ".csv": + return "text/csv"; + + case ".plain": + return "text/plain"; + + case ".richtext": + return "text/richtext"; + + case ".rtf": + return "text/rtf"; + + case ".rtx": + return "text/rtx"; + + case ".sgml": + return "text/sgml"; + + case ".strings": + return "text/strings"; + + case ".url": + return "text/uri-list"; + + case ".H264": + return "video/H264"; + + case ".H265": + return "video/H265"; + + case ".mpeg": + return "video/mpeg"; + + case ".raw": + return "video/raw"; + + default: + return "application/octet-stream"; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs.meta new file mode 100644 index 0000000..2db2bd6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/HttpTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2392eb77f296fcf47aed9054f529ad34 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs new file mode 100644 index 0000000..e81439b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// 多文件集合 + /// + public class MultifileCollection : IEnumerable + { + private readonly HttpRequest m_httpRequest; + + /// + /// 多文件集合 + /// + /// + public MultifileCollection(HttpRequest httpRequest) + { + m_httpRequest = httpRequest; + } + + /// + /// 获取一个迭代器。 + /// + /// + public IEnumerator GetEnumerator() + { + if (m_httpRequest.ContentComplated == null || m_httpRequest.ContentComplated == true) + { + if (m_httpRequest.TryGetContent(out byte[] context)) + { + byte[] boundary = $"--{m_httpRequest.GetBoundary()}".ToUTF8Bytes(); + var indexs = context.IndexOfInclude(0, context.Length, boundary); + if (indexs.Count <= 0) + { + throw new Exception("没有发现由Boundary包裹的数据。"); + } + List files = new List(); + for (int i = 0; i < indexs.Count; i++) + { + if (i + 1 < indexs.Count) + { + InternalFormFile internalFormFile = new InternalFormFile(); + files.Add(internalFormFile); + int index = context.IndexOfFirst(indexs[i] + 3, indexs[i + 1], Encoding.UTF8.GetBytes("\r\n\r\n")); + string line = Encoding.UTF8.GetString(context, indexs[i] + 3, index - indexs[i] - 6); + string[] lines = line.Split(new string[] { ";", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + internalFormFile.DataPair = new NameValueCollection(); + foreach (var item in lines) + { + string[] kv = item.Split(new char[] { ':', '=' }); + if (kv.Length == 2) + { + internalFormFile.DataPair.Add(kv[0].Trim(), kv[1].Replace("\"", String.Empty).Trim()); + } + } + + int length = indexs[i + 1] - (index + 2) - boundary.Length; + byte[] data = new byte[length]; + Array.Copy(context, index + 1, data, 0, length); + //string ssss = Encoding.UTF8.GetString(data); + internalFormFile.Data = data; + } + } + + return files.GetEnumerator(); + } + throw new Exception("管道状态异常"); + } + else + { + throw new Exception("管道状态异常"); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs.meta new file mode 100644 index 0000000..505e6cf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/MultifileCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0555ed4da45b51b4da891b103e88f42c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs new file mode 100644 index 0000000..8499ca8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Http +{ + /// + /// HttpUtility + /// + public static class TouchSocketHttpUtility + { + /// + /// 非缓存上限 + /// + public const int NoCacheMaxSize = 1024 * 1024; + + /// + /// Get关键字 + /// + public const string Get = "GET"; + + /// + /// Post关键字 + /// + public const string Post = "POST"; + + /// + /// Put关键字 + /// + public const string Put = "PUT"; + + /// + /// Delete关键字 + /// + public const string Delete = "DELETE"; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs.meta new file mode 100644 index 0000000..4739308 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/TouchSocketHttpUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e16a1eb99c4493488408b3c05221248 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy.meta new file mode 100644 index 0000000..b54f669 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40cff02b2540ecd4c94e3103d4bf1f19 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs new file mode 100644 index 0000000..cced489 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TouchSocket.Http +{ + /// + /// 处理代理认证凭证 + /// + internal class AuthenticationChallenge + { + /// + /// 构造 + /// + /// 服务器返回的凭证认证类型 + /// 基本凭证用户名密码 + /// 暂时不知道是什么 + public AuthenticationChallenge(string value, NetworkCredential credential, uint nonceCount = 0) + { + Parse(value, credential); + NonceCount = nonceCount; + } + + /// + /// 暂时不知 + /// + public uint NonceCount { get; set; } + + /// + /// 其实用不用他都一样 + /// + public Dictionary Parameters { get; set; } + + /// + /// 凭证类型 + /// + public AuthenticationType Type { get; set; } + + /// + /// 转换成凭证本文 + /// + /// + /// + public override string ToString() + { + if (Type == AuthenticationType.Basic) + return ToBasicString(); + else + throw new Exception("该凭证类型不支持"); + } + + private void Parse(string value, NetworkCredential credential) + { + var chal = value.Split(new[] { ' ' }, 2); + if (chal.Length != 2) + throw new Exception("该凭证类型不支持"); + + var schm = chal[0].ToLower(); + Parameters = ParseParameters(chal[1]); + + if (Parameters.ContainsKey("username") == false) + Parameters.Add("username", credential.Username); + if (Parameters.ContainsKey("password") == false) + Parameters.Add("password", credential.Password); + + /* + * Basic基本类型貌似只需要用户名密码即可 + * if (this.parameters.ContainsKey("uri") == false) + this.parameters.Add("uri", credential.Domain);*/ + + if (schm == "basic") + { + Type = AuthenticationType.Basic; + } + else + throw new Exception("该凭证类型不支持"); + } + + private Dictionary ParseParameters(string value) + { + var res = new Dictionary(); + IEnumerable values = SplitHeaderValue(value, ','); + foreach (var param in values) + { + var i = param.IndexOf('='); + var name = i > 0 ? param.Substring(0, i).Trim() : null; + var val = i < 0 + ? param.Trim().Trim('"') + : i < param.Length - 1 + ? param.Substring(i + 1).Trim().Trim('"') + : string.Empty; + + res.Add(name, val); + } + return res; + } + + private IEnumerable SplitHeaderValue(string value, params char[] separators) + { + var len = value.Length; + var end = len - 1; + + var buff = new StringBuilder(32); + var escaped = false; + var quoted = false; + + for (var i = 0; i <= end; i++) + { + var c = value[i]; + buff.Append(c); + if (c == '"') + { + if (escaped) + { + escaped = false; + continue; + } + quoted = !quoted; + continue; + } + if (c == '\\') + { + if (i == end) + break; + if (value[i + 1] == '"') + escaped = true; + continue; + } + if (Array.IndexOf(separators, c) > -1) + { + if (quoted) + continue; + buff.Length -= 1; + yield return buff.ToString(); + buff.Length = 0; + continue; + } + } + yield return buff.ToString(); + } + + private string ToBasicString() + { + var userPass = $"{Parameters["username"]}:{Parameters["password"]}"; + var cred = Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass)); + return "Basic " + cred; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs.meta new file mode 100644 index 0000000..a0fcf33 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 72b148c05c89e634eb1238d28b026615 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs new file mode 100644 index 0000000..b941948 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http +{ + /// + /// 代理身份认证类型 + /// + public enum AuthenticationType + { /// + /// 不允许身份认证 + /// + None, + + /// + /// 指定摘要身份验证。 + /// + Digest = 1, + + /// + /// 指定基本身份验证。 + /// + Basic = 8, + + /// + /// 指定匿名身份验证。 + /// + Anonymous = 0x8000 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs.meta new file mode 100644 index 0000000..e3f930e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c947b4636f74504d9fb0a2aaf5651b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs new file mode 100644 index 0000000..56ac857 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Http +{ + /// + /// 代理身份认证 + /// + public class NetworkCredential + { + /// + /// 构造 + /// + /// + /// + /// 基本认证应该不需要这个 + /// + /// + /// + public NetworkCredential(string username, string password, string domain, params string[] roles) + { + if (username == null) + throw new ArgumentNullException("username"); + + if (username.Length == 0) + throw new ArgumentException("An empty string.", "username"); + Username = username; + Password = password; + Domain = domain; + Roles = roles; + } + + /// + /// 凭证用户名 + /// + + public string Username { get; } + + /// + /// 凭证密码 + /// + public string Password { get; } + + /// + /// Domain + /// + public string Domain { get; } + + /// + /// Roles + /// + public string[] Roles { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs.meta new file mode 100644 index 0000000..8121e69 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca58ed0f22ee410428fd1694dc6d7fec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components.meta new file mode 100644 index 0000000..c3541cf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f92f0c9b9d0df94ab11e0835332dfec +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs new file mode 100644 index 0000000..cd4db89 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs @@ -0,0 +1,238 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http客户端 + /// + public class HttpClient : HttpClientBase + { + } + + /// + /// Http客户端基类 + /// + public class HttpClientBase : TcpClientBase, IHttpClient + { + private readonly object m_requestLocker = new object(); + private bool m_getContent; + private readonly WaitData m_waitData; + + /// + /// 构造函数 + /// + public HttpClientBase() + { + m_waitData = new WaitData(); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default) + { + lock (m_requestLocker) + { + m_getContent = false; + using (ByteBlock byteBlock = new ByteBlock()) + { + request.Build(byteBlock); + + m_waitData.Reset(); + m_waitData.SetCancellationToken(token); + + this.DefaultSend(byteBlock); + if (onlyRequest) + { + return default; + } + + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + return default; + + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default) + { + lock (m_requestLocker) + { + m_getContent = true; + using (ByteBlock byteBlock = new ByteBlock()) + { + request.Build(byteBlock); + + m_waitData.Reset(); + m_waitData.SetCancellationToken(token); + + this.DefaultSend(byteBlock); + if (onlyRequest) + { + return default; + } + + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + return default; + + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_waitData?.Dispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + if (Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy) + { + IPHost proxyHost = httpProxy.Host; + var credential = httpProxy.Credential; + IPHost remoteHost = Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + try + { + Config.SetRemoteIPHost(proxyHost); + base.Connect(timeout); + HttpRequest httpRequest = new HttpRequest(); + httpRequest.InitHeaders() + .SetHost(remoteHost.Host) + .SetUrl(remoteHost.Host, true) + .AsMethod("CONNECT"); + var response = Request(httpRequest, timeout: timeout); + if (response.IsProxyAuthenticationRequired) + { + if (credential is null) + { + throw new Exception("未指定代理的凭据。"); + } + string authHeader = response.GetHeader(HttpHeaders.ProxyAuthenticate); + if (authHeader.IsNullOrEmpty()) + { + throw new Exception("未指定代理身份验证质询。"); + } + + var ares = new AuthenticationChallenge(authHeader, credential); + + httpRequest.SetHeader(HttpHeaders.ProxyAuthorization, ares.ToString()); + if (response.CloseConnection) + { + base.Close("代理要求关闭连接,随后重写连接。"); + base.Connect(timeout); + } + + response = Request(httpRequest, timeout: timeout); + } + + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + } + finally + { + Config.SetRemoteIPHost(remoteHost); + } + } + else + { + base.Connect(timeout); + } + return this; + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + base.HandleReceivedData(byteBlock, requestInfo); + + if (requestInfo is HttpResponse response) + { + if (m_getContent) + { + response.TryGetContent(out _); + } + m_waitData.Set(response); + } + } + + /// + /// + /// + /// + protected override void OnConnecting(ConnectingEventArgs e) + { + Protocol = Protocol.Http; + SetDataHandlingAdapter(new HttpClientDataHandlingAdapter()); + base.OnConnecting(e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs.meta new file mode 100644 index 0000000..45dc525 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a08db3b6e925c14dac7bfcd23a6c501 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs new file mode 100644 index 0000000..c5e483a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HTTP/HTTPS服务器 + /// + public class HttpService : TcpService, IHttpService where TClient : HttpSocketClient + { + } + + /// + /// HTTP/HTTPS服务器 + /// + public class HttpService : HttpService + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs.meta new file mode 100644 index 0000000..37af802 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe68517850a34d94e9ec6e7071cec2b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs new file mode 100644 index 0000000..ad79845 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// http辅助类 + /// + public class HttpSocketClient : SocketClient, IHttpSocketClient + { + /// + /// 构造函数 + /// + public HttpSocketClient() + { + Protocol = Protocol.Http; + } + + /// + /// + /// + /// + protected override void OnConnecting(OperationEventArgs e) + { + SetDataHandlingAdapter(new HttpServerDataHandlingAdapter()); + base.OnConnecting(e); + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (requestInfo is HttpRequest request) + { + OnReceivedHttpRequest(request); + } + } + + /// + /// 当收到到Http请求时。覆盖父类方法将不会触发插件。 + /// + protected virtual void OnReceivedHttpRequest(HttpRequest request) + { + HttpContextEventArgs args = new HttpContextEventArgs(new HttpContext(request)); + + switch (request.Method) + { + case TouchSocketHttpUtility.Get: + { + PluginsManager.Raise("OnGet", this, args); + break; + } + case TouchSocketHttpUtility.Post: + { + PluginsManager.Raise("OnPost", this, args); + break; + } + case TouchSocketHttpUtility.Put: + { + PluginsManager.Raise("OnPut", this, args); + break; + } + case TouchSocketHttpUtility.Delete: + { + PluginsManager.Raise("OnDelete", this, args); + break; + } + default: + PluginsManager.Raise("OnReceivedOtherHttpRequest", this, args); + break; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs.meta new file mode 100644 index 0000000..400f35b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Components/HttpSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47068fed96b93884d957dda39ddf719b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config.meta new file mode 100644 index 0000000..55677b6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ce136f5521ea5546ab3b91a29d1e53c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs new file mode 100644 index 0000000..c85eae9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs @@ -0,0 +1,94 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Http; + +namespace TouchSocket.Sockets +{ + /// + /// HttpConfigExtensions + /// + public static class HttpConfigExtensions + { + #region 创建 + + /// + /// 构建Http类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithHttpClient(this TouchSocketConfig config) where TClient : IHttpClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建Http类客户端,并连接 + /// + /// + /// + public static HttpClient BuildWithHttpClient(this TouchSocketConfig config) + { + return BuildWithHttpClient(config); + } + + /// + /// 构建Http类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithHttpService(this TouchSocketConfig config) where TService : IHttpService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建Http类服务器,并启动。 + /// + /// + /// + public static HttpService BuildWithHttpService(this TouchSocketConfig config) + { + return BuildWithHttpService(config); + } + + #endregion 创建 + + /// + /// Http代理 + /// + public static readonly DependencyProperty HttpProxyProperty = + DependencyProperty.Register("HttpProxy", typeof(HttpConfigExtensions), null); + + /// + ///设置Http代理 + /// + /// + /// + /// + public static TouchSocketConfig SetHttpProxy(this TouchSocketConfig config, HttpProxy value) + { + config.SetValue(HttpProxyProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs.meta new file mode 100644 index 0000000..10dbc7b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Config/HttpConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e797b9ab2a2af34418b6977c552f3faf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter.meta new file mode 100644 index 0000000..233a5e7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e7be221c314d6f48a835586ec786a96 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs new file mode 100644 index 0000000..95440a7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs @@ -0,0 +1,206 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http客户端数据处理适配器 + /// + public class HttpClientDataHandlingAdapter : NormalDataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock tempByteBlock; + + private static readonly byte[] m_rnCode = Encoding.UTF8.GetBytes("\r\n"); + private HttpResponse m_httpResponse; + + private long m_surLen; + + private Task m_task; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (tempByteBlock == null) + { + byteBlock.Pos = 0; + Single(byteBlock, false); + } + else + { + tempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = tempByteBlock; + tempByteBlock = null; + block.Pos = 0; + Single(block, true); + } + } + + private void Cache(ByteBlock byteBlock) + { + if (byteBlock.CanReadLen > 0) + { + tempByteBlock = new ByteBlock(); + tempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + if (tempByteBlock.Len > MaxPackageSize) + { + OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + } + + private FilterResult ReadChunk(ByteBlock byteBlock) + { + int position = byteBlock.Pos; + int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, m_rnCode); + if (index > 0) + { + int headerLength = index - byteBlock.Pos; + string hex = Encoding.ASCII.GetString(byteBlock.Buffer, byteBlock.Pos, headerLength - 1); + int count = hex.ByHexStringToInt32(); + byteBlock.Pos += headerLength + 1; + + if (count >= 0) + { + if (count > byteBlock.CanReadLen) + { + byteBlock.Pos = position; + return FilterResult.Cache; + } + + m_httpResponse.InternalInput(byteBlock.Buffer, byteBlock.Pos, count); + byteBlock.Pos += count; + byteBlock.Pos += 2; + return FilterResult.GoOn; + } + else + { + byteBlock.Pos += 2; + return FilterResult.Success; + } + } + else + { + return FilterResult.Cache; + } + } + + private void Single(ByteBlock byteBlock, bool dis) + { + try + { + while (byteBlock.CanReadLen > 0) + { + if (m_httpResponse == null) + { + m_httpResponse = new HttpResponse(Client, false); + if (m_httpResponse.ParsingHeader(byteBlock, byteBlock.CanReadLen)) + { + byteBlock.Pos++; + if (m_httpResponse.IsChunk || m_httpResponse.ContentLength > byteBlock.CanReadLength) + { + m_surLen = m_httpResponse.ContentLength; + m_task = EasyTask.Run(m_httpResponse, (res) => + { + GoReceived(null, res); + }); + } + else + { + byteBlock.Read(out byte[] buffer, (int)m_httpResponse.ContentLength); + m_httpResponse.SetContent(buffer); + GoReceived(null, m_httpResponse); + m_httpResponse = null; + } + } + else + { + Cache(byteBlock); + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + return; + } + } + if (m_httpResponse != null) + { + if (m_httpResponse.IsChunk) + { + switch (ReadChunk(byteBlock)) + { + case FilterResult.Cache: + Cache(byteBlock); + return; + + case FilterResult.Success: + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + break; + + case FilterResult.GoOn: + default: + break; + } + } + else if (m_surLen > 0) + { + if (byteBlock.CanRead) + { + int len = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + m_httpResponse.InternalInput(byteBlock.Buffer, byteBlock.Pos, len); + m_surLen -= len; + byteBlock.Pos += len; + if (m_surLen == 0) + { + m_httpResponse.InternalInput(null, 0, 0); + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + } + } + } + else + { + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + } + } + } + } + finally + { + if (dis) + { + byteBlock.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..73fcc4e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 178c7fb58d7b85d48bc6c6c8d814e9c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs new file mode 100644 index 0000000..9d4dd62 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs @@ -0,0 +1,146 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http服务器数据处理适配器 + /// + public class HttpServerDataHandlingAdapter : NormalDataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock tempByteBlock; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (tempByteBlock == null) + { + byteBlock.Pos = 0; + Single(byteBlock, false); + } + else + { + tempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = tempByteBlock; + tempByteBlock = null; + block.Pos = 0; + Single(block, true); + } + } + + private HttpRequest m_httpRequest; + private Task m_task; + private long m_surLen; + + private void Single(ByteBlock byteBlock, bool dis) + { + try + { + while (byteBlock.CanReadLen > 0) + { + if (m_httpRequest == null) + { + m_httpRequest = new HttpRequest(Client, true); + if (m_httpRequest.ParsingHeader(byteBlock, byteBlock.CanReadLen)) + { + byteBlock.Pos++; + if (m_httpRequest.ContentLength > byteBlock.CanReadLength) + { + m_surLen = m_httpRequest.ContentLength; + + m_task = EasyTask.Run(m_httpRequest, (res) => + { + GoReceived(null, res); + }); + } + else + { + byteBlock.Read(out byte[] buffer, (int)m_httpRequest.ContentLength); + m_httpRequest.SetContent(buffer); + GoReceived(null, m_httpRequest); + m_httpRequest = null; + } + } + else + { + Cache(byteBlock); + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + return; + } + } + + if (m_surLen > 0) + { + if (byteBlock.CanRead) + { + int len = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + m_httpRequest.InternalInput(byteBlock.Buffer, byteBlock.Pos, len); + m_surLen -= len; + byteBlock.Pos += len; + if (m_surLen == 0) + { + m_httpRequest.InternalInput(null, 0, 0); + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + } + } + } + else + { + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + } + } + } + finally + { + if (dis) + { + byteBlock.Dispose(); + } + } + } + + private void Cache(ByteBlock byteBlock) + { + if (byteBlock.CanReadLen > 0) + { + tempByteBlock = new ByteBlock(); + tempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + if (tempByteBlock.Len > MaxPackageSize) + { + OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..5e8f2c1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4583f7b35b1be1f4d920b312499ef383 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs new file mode 100644 index 0000000..3773da0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +/// +/// HTTP上下文事件委托 +/// +/// +/// +/// +public delegate void HttpContextEventHandler(TClient client, HttpContextEventArgs e); \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs.meta new file mode 100644 index 0000000..e2830a9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/DelegateCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d665008fc3179a40b7ed6efad6d04c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum.meta new file mode 100644 index 0000000..e42794b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f3b2bc8bdebc0142b56d21b9fbeec77 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs new file mode 100644 index 0000000..dfebd80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.ComponentModel; + +namespace TouchSocket.Http +{ + /// + /// 请求头枚举 + /// + public enum HttpHeaders : byte + { + /// + /// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。 + /// + [Description("cache-control")] + CacheControl = 0, + + /// + /// Connection 标头,指定特定连接需要的选项。 + /// + [Description("connection")] + Connection = 1, + + /// + /// Date 标头,指定开始创建请求的日期和时间。 + /// + [Description("date")] + Date = 2, + + /// + /// Keep-Alive 标头,指定用以维护持久性连接的参数。 + /// + [Description("keep-alive")] + KeepAlive = 3, + + /// + /// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。 + /// + [Description("pragma")] + Pragma = 4, + + /// + /// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。 + /// + [Description("trailer")] + Trailer = 5, + + /// + /// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。 + /// + [Description("transfer-encoding")] + TransferEncoding = 6, + + /// + /// Upgrade 标头,指定客户端支持的附加通信协议。 + /// + [Description("upgrade")] + Upgrade = 7, + + /// + /// Via 标头,指定网关和代理程序要使用的中间协议。 + /// + [Description("via")] + Via = 8, + + /// + /// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。 + /// + [Description("warning")] + Warning = 9, + + /// + /// Allow 标头,指定支持的 HTTP 方法集。 + /// + [Description("allow")] + Allow = 10, + + /// + /// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。 + /// + [Description("content-length")] + ContentLength = 11, + + /// + /// Content-Type 标头,指定伴随正文数据的 MIME 类型。 + /// + [Description("content-type")] + ContentType = 12, + + /// + /// Content-Encoding 标头,指定已应用于伴随正文数据的编码。 + /// + [Description("content-encoding")] + ContentEncoding = 13, + + /// + /// Content-Langauge 标头,指定伴随正文数据的自然语言。 + /// + [Description("content-langauge")] + ContentLanguage = 14, + + /// + /// Content-Location 标头,指定可从其中获得伴随正文的 URI。 + /// + [Description("content-location")] + ContentLocation = 15, + + /// + /// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。 + /// + [Description("content-md5")] + ContentMd5 = 16, + + /// + /// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。 + /// + [Description("content-range")] + ContentRange = 17, + + /// + /// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。 + /// + [Description("expires")] + Expires = 18, + + /// + /// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。 + /// + [Description("last-modified")] + LastModified = 19, + + /// + /// Accept 标头,指定响应可接受的 MIME 类型。 + /// + [Description("accept")] + Accept = 20, + + /// + /// Accept-Charset 标头,指定响应可接受的字符集。 + /// + [Description("accept-charset")] + AcceptCharset = 21, + + /// + /// Accept-Encoding 标头,指定响应可接受的内容编码。 + /// + [Description("accept-encoding")] + AcceptEncoding = 22, + + /// + /// Accept-Langauge 标头,指定响应首选的自然语言。 + /// + [Description("accept-langauge")] + AcceptLanguage = 23, + + /// + /// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。 + /// + [Description("authorization")] + Authorization = 24, + + /// + /// Cookie 标头,指定向服务器提供的 Cookie 数据。 + /// + [Description("cookie")] + Cookie = 25, + + /// + /// Expect 标头,指定客户端要求的特定服务器行为。 + /// + [Description("expect")] + Expect = 26, + + /// + /// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。 + /// + [Description("from")] + From = 27, + + /// + /// Host 标头,指定所请求资源的主机名和端口号。 + /// + [Description("host")] + Host = 28, + + /// + /// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。 + /// + [Description("if-match")] + IfMatch = 29, + + /// + /// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("if-modified-since")] + IfModifiedSince = 30, + + /// + /// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。 + /// + [Description("if-none-match")] + IfNoneMatch = 31, + + /// + /// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。 + /// + [Description("if-range")] + IfRange = 32, + + /// + /// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("if-unmodified-since")] + IfUnmodifiedSince = 33, + + /// + /// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。 + /// + [Description("max-forwards")] + MaxForwards = 34, + + /// + /// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。 + /// + [Description("proxy-authorization")] + ProxyAuthorization = 35, + + /// + /// Referer 标头,指定从中获得请求 URI 的资源的 URI。 + /// + [Description("referer")] + Referer = 36, + + /// + /// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。 + /// + [Description("range")] + Range = 37, + + /// + /// TE 标头,指定响应可接受的传输编码方式。 + /// + [Description("te")] + Te = 38, + + /// + /// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。 + /// + [Description("translate")] + Translate = 39, + + /// + /// User-Agent 标头,指定有关客户端代理的信息。 + /// + [Description("user-agent")] + UserAgent = 40, + + /// + /// Accept-Ranges 标头,指定服务器接受的范围。 + /// + [Description("accept-ranges")] + AcceptRanges = 41, + + /// + /// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。 + /// + [Description("age")] + Age = 42, + + /// + /// Etag 标头,指定请求的变量的当前值。 + /// + [Description("etag")] + ETag = 43, + + /// + /// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。 + /// + [Description("location")] + Location = 44, + + /// + /// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。 + /// + [Description("proxy-authenticate")] + ProxyAuthenticate = 45, + + /// + /// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。 + /// + [Description("retry-after")] + RetryAfter = 46, + + /// + /// Server 标头,指定关于起始服务器代理的信息。 + /// + [Description("server")] + Server = 47, + + /// + /// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。 + /// + [Description("set-cookie")] + SetCookie = 48, + + /// + /// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。 + /// + [Description("vary")] + Vary = 49, + + /// + /// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。 + /// + [Description("www-authenticate")] + WwwAuthenticate = 50, + + /// + /// Origin。 + /// + [Description("origin")] + Origin = 51, + + /// + /// Content-Disposition + /// + [Description("content-disposition")] + ContentDisposition = 52 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs.meta new file mode 100644 index 0000000..c694bf3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Enum/HttpHeaders.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea4c3cf69da9f1d4da5264abacb22f4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs.meta new file mode 100644 index 0000000..badb7a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17a4f40684ad6f040827f6d2f49fee47 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs new file mode 100644 index 0000000..48d186d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// Http请求事件类 + /// + public class HttpContextEventArgs : TouchSocketEventArgs + { + /// + /// Http上下文 + /// + public HttpContext Context { get; } + + /// + /// 构造函数 + /// + /// + public HttpContextEventArgs(HttpContext context) + { + Context = context; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs.meta new file mode 100644 index 0000000..ff9404a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 132d179867ab9a147878ae6ac595346f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions.meta new file mode 100644 index 0000000..89bf87d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48462993a007a3346a03ad9e99f54769 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs new file mode 100644 index 0000000..e9157a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs @@ -0,0 +1,474 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http扩展辅助 + /// + public static class HttpExtensions + { + /// + /// 根据字符串获取枚举 + /// + /// + /// + /// + /// + public static bool GetEnum(string str, out T result) where T : struct + { + return Enum.TryParse(str, out result); + } + + #region HttpBase + + #region 设置内容 + + /// + /// 从Json + /// + /// + /// + /// + public static T FromJson(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "application/json;charset=UTF-8"); + return httpRequest; + } + + /// + /// 从文本 + /// + /// + /// + /// + public static T FromText(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "text/plain;charset=UTF-8"); + return httpRequest; + } + + /// + /// 从Xml格式 + /// + /// + /// + /// + public static T FromXML(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "application/xml;charset=UTF-8"); + return httpRequest; + } + + #endregion 设置内容 + + /// + /// 获取Body的字符串 + /// + /// + /// + public static string GetBody(this HttpBase httpBase) + { + if (httpBase.TryGetContent(out byte[] data)) + { + return Encoding.UTF8.GetString(data); + } + throw new Exception("获取数据体错误。"); + } + + /// + /// 当数据类型为multipart/form-data时,获取boundary + /// + /// + /// + /// + public static string GetBoundary(this HttpBase httpBase) + { + if (httpBase.ContentType.IsNullOrEmpty()) + { + return string.Empty; + } + string[] strs = httpBase.ContentType.Split(';'); + if (strs.Length == 2) + { + strs = strs[1].Split('='); + if (strs.Length == 2) + { + return strs[1].Trim(); + } + } + return string.Empty; + } + + /// + /// 设置内容 + /// + /// + /// + /// + /// + public static T SetContent(this T httpBase, string content, Encoding encoding = null) where T : HttpBase + { + httpBase.SetContent(Encoding.UTF8.GetBytes(content)); + return httpBase; + } + + /// + /// 设置数据体长度 + /// + /// + /// + public static T SetContentLength(this T httpBase, long value) where T : HttpBase + { + httpBase.ContentLength = value; + return httpBase; + } + + /// + /// 从扩展名设置内容类型,必须以“.”开头 + /// + /// + /// + /// + public static T SetContentTypeByExtension(this T httpBase, string extension) where T : HttpBase + { + string type = HttpTools.GetContentTypeFromExtension(extension); + httpBase.SetHeader(HttpHeaders.ContentType.GetDescription(), type); + httpBase.ContentType = type; + return httpBase; + } + + /// + /// 设置头值 + /// + /// + /// + /// + public static T SetHeader(this T httpBase, HttpHeaders header, string value) where T : HttpBase + { + httpBase.SetHeaderByKey(header.GetDescription(), value); + return httpBase; + } + + /// + /// 设置头值 + /// + /// + /// + /// + public static T SetHeader(this T httpBase, string fieldName, string value) where T : HttpBase + { + httpBase.SetHeaderByKey(fieldName.ToLower(), value); + return httpBase; + } + + /// + /// 写入 + /// + /// + /// + public static T WriteContent(this T httpBase, byte[] buffer) where T : HttpBase + { + httpBase.WriteContent(buffer, 0, buffer.Length); + return httpBase; + } + + #endregion HttpBase + + #region HttpRequest + + /// + /// 获取多文件集合。如果不存在,则返回null。 + /// + /// + /// + /// + public static MultifileCollection GetMultifileCollection(this TRequest request) where TRequest : HttpRequest + { + if (request.GetBoundary().IsNullOrEmpty()) + { + return null; + } + else + { + return new MultifileCollection(request); + } + } + + /// + /// 初始化常规的请求头。 + /// 包含: + /// + /// Connection:keep-alive + /// Pragma:no-cache + /// UserAgent:TouchSocket.Http + /// Accept:*/* + /// AcceptEncoding:deflate, br + /// + /// + /// + /// + public static TRequest InitHeaders(this TRequest request) where TRequest : HttpRequest + { + request.SetHeader(HttpHeaders.Connection, "keep-alive"); + request.SetHeader(HttpHeaders.Pragma, "no-cache"); + request.SetHeader(HttpHeaders.UserAgent, "TouchSocket.Http"); + request.SetHeader(HttpHeaders.Accept, "*/*"); + request.SetHeader(HttpHeaders.AcceptEncoding, "deflate, br"); + return request; + } + + /// + /// 添加Host请求头 + /// + /// + /// + /// + public static TRequest SetHost(this TRequest request, string host) where TRequest : HttpRequest + { + request.SetHeader(HttpHeaders.Host, host); + return request; + } + + /// + /// 对比不包含参数的Url。其中有任意一方为null,则均返回False。 + /// + /// + /// + /// + public static bool UrlEquals(this TRequest httpRequest, string url) where TRequest : HttpRequest + { + if (string.IsNullOrEmpty(httpRequest.RelativeURL) || string.IsNullOrEmpty(url)) + { + return false; + } + if (httpRequest.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + return false; + } + + #region 设置函数 + + /// + /// 作为Delete访问 + /// + /// + /// + public static TRequest AsDelete(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Delete; + return httpRequest; + } + + /// + /// 作为Get访问 + /// + /// + /// + public static TRequest AsGet(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Get; + return httpRequest; + } + + /// + /// 作为指定函数 + /// + /// + /// + /// + public static TRequest AsMethod(this TRequest request, string method) where TRequest : HttpRequest + { + request.Method = method; + return request; + } + + /// + /// 作为Post访问 + /// + /// + /// + public static TRequest AsPost(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Post; + return httpRequest; + } + + /// + /// 作为Put访问 + /// + /// + /// + public static TRequest AsPut(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Put; + return httpRequest; + } + + #endregion 设置函数 + + #endregion HttpRequest + + #region HttpResponse + + /// + /// 路径文件没找到 + /// + /// + /// + public static TResponse UrlNotFind(this TResponse response) where TResponse : HttpResponse + { + response.SetContent("

404 -RRQM Not Found

"); + response.StatusCode = "404"; + response.ContentType = "text/html;charset=utf-8"; + return response; + } + + /// + /// 从文件响应。 + /// 当response支持持续写入时,会直接回复响应。并阻塞执行,直到完成。所以在执行该方法之前,请确保已设置完成所有状态字 + /// 当response不支持持续写入时,会填充Content,且不会响应,需要自己执行Build,并发送。 + /// + /// 响应 + /// 请求头,用于尝试续传,为null时则不续传。 + /// 文件路径 + /// 文件名,不设置时会获取路径文件名 + /// 最大速度(仅企业版有效)。 + /// 读取长度。 + /// + /// + /// + public static TResponse FromFile(this TResponse response, string filePath, HttpRequest request, string fileName = null, int maxSpeed = 1024 * 1024 * 10, int bufferLen = 1024 * 64) where TResponse : HttpResponse + { + using (var reader = FilePool.GetReader(filePath)) + { + response.SetContentTypeByExtension(Path.GetExtension(filePath)); + var contentDisposition = "attachment;" + "filename=" /*+ System.Web.HttpUtility.UrlEncode(fileName == null ? Path.GetFileName(filePath) : fileName)*/; + response.SetHeader(HttpHeaders.ContentDisposition, contentDisposition) + .SetHeader(HttpHeaders.AcceptRanges, "bytes"); + + if (response.CanWrite) + { + HttpRange httpRange; + string range = request?.GetHeader(HttpHeaders.Range); + if (string.IsNullOrEmpty(range)) + { + response.SetStatus(); + response.ContentLength = reader.FileStorage.FileInfo.Length; + httpRange = new HttpRange() { Start = 0, Length = reader.FileStorage.FileInfo.Length }; + } + else + { + httpRange = HttpRange.GetRange(range, reader.FileStorage.FileInfo.Length); + if (httpRange == null) + { + response.ContentLength = reader.FileStorage.FileInfo.Length; + httpRange = new HttpRange() { Start = 0, Length = reader.FileStorage.FileInfo.Length }; + } + else + { + response.SetContentLength(httpRange.Length) + .SetStatus("206", "Partial Content") + .SetHeader(HttpHeaders.ContentRange, string.Format("bytes {0}-{1}/{2}", httpRange.Start, httpRange.Length + httpRange.Start - 1, reader.FileStorage.FileInfo.Length)); + } + } + reader.Position = httpRange.Start; + long surLen = httpRange.Length; + FlowGate flowGate = new FlowGate(); + flowGate.Maximum = maxSpeed; + + using (ByteBlock block = new ByteBlock(bufferLen)) + { + while (surLen > 0) + { + int r = reader.Read(block.Buffer, 0, (int)Math.Min(bufferLen, surLen)); + if (r == 0) + { + break; + } + flowGate.AddCheckWait(r); + response.WriteContent(block.Buffer, 0, r); + surLen -= r; + } + } + } + else + { + if (reader.FileStorage.FileInfo.Length > 1024 * 1024) + { + throw new OverlengthException("当该对象不支持写入时,仅支持1Mb以内的文件。"); + } + + using (ByteBlock byteBlock = new ByteBlock((int)reader.FileStorage.FileInfo.Length)) + { + using (ByteBlock block = new ByteBlock(bufferLen)) + { + while (true) + { + int r = reader.Read(block.Buffer, 0, bufferLen); + if (r == 0) + { + break; + } + byteBlock.Write(block.Buffer, 0, r); + } + response.SetContent(byteBlock.ToArray()); + } + } + } + } + return response; + } + + /// + /// 设置文件类型。 + /// + /// + /// + /// + public static TResponse SetContentTypeFromFileName(this TResponse response, string fileName) where TResponse : HttpResponse + { + var contentDisposition = "attachment;" + "filename=" /*+ System.Web.HttpUtility.UrlEncode(fileName)*/; + response.SetHeader(HttpHeaders.ContentDisposition, contentDisposition); + return response; + } + + /// + /// 设置状态,并且附带时间戳。 + /// + /// + /// + /// + /// + public static TResponse SetStatus(this TResponse response, string status = "200", string msg = "Success") where TResponse : HttpResponse + { + response.StatusCode = status; + response.StatusMessage = msg; + response.SetHeader(HttpHeaders.Server, $"TouchSocket.Http {HttpBase.ServerVersion}"); + response.SetHeader(HttpHeaders.Date, DateTime.Now.ToGMTString("r")); + return response; + } + + #endregion HttpResponse + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs.meta new file mode 100644 index 0000000..5b620a3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d13216478cba98b47be81d763622382e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs new file mode 100644 index 0000000..1e681c6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Core +{ + /// + /// HttpPluginsManagerExtension + /// + public static class HttpPluginsManagerExtension + { + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + /// + /// + public static DefaultHttpServicePlugin UseDefaultHttpServicePlugin(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..bac6092 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6001de705c6da734e897f19fbd54f44a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface.meta new file mode 100644 index 0000000..278de84 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1486a9cbd6c8c3e4484851f482dbdfd7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs new file mode 100644 index 0000000..057b51d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http接口 + /// + public interface IHttpPlugin : IPlugin + { + /// + /// 在收到Delete时 + /// + /// + /// + [AsyncRaiser] + void OnDelete(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Delete时 + /// + /// + /// + /// + Task OnDeleteAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Get时 + /// + /// + /// + [AsyncRaiser] + void OnGet(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Get时 + /// + /// + /// + /// + Task OnGetAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Post时 + /// + /// + /// + [AsyncRaiser] + void OnPost(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Post时 + /// + /// + /// + /// + Task OnPostAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Put时 + /// + /// + /// + [AsyncRaiser] + void OnPut(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Put时 + /// + /// + /// + /// + Task OnPutAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到其他Http请求时 + /// + /// + /// + [AsyncRaiser] + void OnReceivedOtherHttpRequest(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到其他Http请求时 + /// + /// + /// + /// + Task OnReceivedOtherHttpRequestAsync(ITcpClientBase client, HttpContextEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs.meta new file mode 100644 index 0000000..17507c8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/HttpPluginInterface.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e40fc2743caa154b9a68941b8d794d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs new file mode 100644 index 0000000..9c8232c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Specialized; + +namespace TouchSocket.Http +{ + /// + /// 表单文件 + /// + public interface IFormFile + { + /// + /// 获取Content-Disposition + /// + string ContentDisposition { get; } + + /// + /// 获取Content-Type + /// + string ContentType { get; } + + /// + /// 实际的数据 + /// + public byte[] Data { get; } + + /// + /// 数据对 + /// + public NameValueCollection DataPair { get; } + + /// + /// 获取file name + /// + string FileName { get; } + + /// + /// 文件长度。在数据接收完成之前,该值为-1; + /// + long Length { get; } + + /// + /// 获取name字段 + /// + string Name { get; } + + ///// + ///// 读取文件数据 //太麻烦先不实现 + ///// + //public int Read(byte[] buffer, int offset, int count); + } + + internal class InternalFormFile : IFormFile + { + public string ContentDisposition => DataPair["Content-Disposition"]; + + public string ContentType => DataPair["Content-Type"]; + + public byte[] Data { get; set; } + public NameValueCollection DataPair { get; set; } + public string FileName => DataPair["filename"]; + public long Length => Data == null ? 0 : Data.Length; + + public string Name => DataPair["name"]; + //public int Read(byte[] buffer, int offset, int count) + //{ + // return this.ReadAction(buffer, offset, count); + //} + + //public Func ReadAction { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs.meta new file mode 100644 index 0000000..02dd639 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IFormFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1558a0cad8b5114898dac1f032abfd5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs new file mode 100644 index 0000000..481efa7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http终端基础接口 + /// + public interface IHttpClientBase : ITcpClientBase + { + } + + /// + /// Http服务器终端接口 + /// + public interface IHttpSocketClient : IHttpClientBase + { + } + + /// + /// Http终端接口 + /// + public interface IHttpClient : ITcpClient, IHttpClientBase + { + /// + /// 发起请求 + /// + /// 请求体 + /// 仅仅请求,而不等待结果 + /// 等待超时时间 + /// 结束等待令箭 + /// + HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default); + + /// + /// 发起请求,并获取数据体 + /// + /// 请求体 + /// 仅仅请求,而不等待结果 + /// 等待超时时间 + /// 结束等待令箭 + /// + public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs.meta new file mode 100644 index 0000000..4c0a752 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9947df10f6c59b445805ef151157e827 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs new file mode 100644 index 0000000..14e28e1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HttpService接口 + /// + public interface IHttpService : ITcpService + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs.meta new file mode 100644 index 0000000..1203548 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Interface/IHttpService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ea558bbd7b90714e9b429e8706c86f8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins.meta new file mode 100644 index 0000000..1c263b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28e3feb4b38396d419989c971fb25408 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs new file mode 100644 index 0000000..6608592 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + public class DefaultHttpServicePlugin : HttpPluginBase + { + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + public DefaultHttpServicePlugin() + { + Order = int.MinValue; + } + + /// + /// + /// + /// + /// + /// + protected override void OnLoadingConfig(object sender, ConfigEventArgs e) + { + if (!(sender is IService)) + { + throw new Exception("该插件仅可用于服务器。"); + } + base.OnLoadingConfig(sender, e); + } + + /// + /// + /// + /// + /// + protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnGet(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnPost(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPut(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnPut(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnDelete(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnDelete(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedOtherHttpRequest(HttpSocketClient client, HttpContextEventArgs e) + { + switch (e.Context.Request.Method.ToUpper()) + { + case "OPTIONS": + { + e.Context.Response + .SetStatus() + .SetHeader("Access-Control-Allow-Origin", "*") + .SetHeader("Access-Control-Allow-Headers", "*") + .SetHeader("Allow", "OPTIONS, GET, POST") + .SetHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS") + .Answer(); + break; + } + default: + e.Context.Response.UrlNotFind().Answer(); + break; + } + base.OnReceivedOtherHttpRequest(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs.meta new file mode 100644 index 0000000..b8d1a34 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 78803d62e2f84c24bab1914ddd397657 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs new file mode 100644 index 0000000..286f1e1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs @@ -0,0 +1,185 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http扩展基类 + /// + public class HttpPluginBase : HttpPluginBase + { + } + + /// + /// Http扩展基类 + /// + public abstract class HttpPluginBase : TcpPluginBase, IHttpPlugin + { + void IHttpPlugin.OnDelete(ITcpClientBase client, HttpContextEventArgs e) + { + OnDelete((TClient)client, e); + } + + Task IHttpPlugin.OnDeleteAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnDeleteAsync((TClient)client, e); + } + + void IHttpPlugin.OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + OnGet((TClient)client, e); + } + + Task IHttpPlugin.OnGetAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnGetAsync((TClient)client, e); + } + + void IHttpPlugin.OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + OnPost((TClient)client, e); + } + + Task IHttpPlugin.OnPostAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnPostAsync((TClient)client, e); + } + + void IHttpPlugin.OnPut(ITcpClientBase client, HttpContextEventArgs e) + { + OnPut((TClient)client, e); + } + + Task IHttpPlugin.OnPutAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnPutAsync((TClient)client, e); + } + + void IHttpPlugin.OnReceivedOtherHttpRequest(ITcpClientBase client, HttpContextEventArgs e) + { + OnReceivedOtherHttpRequest((TClient)client, e); + } + + Task IHttpPlugin.OnReceivedOtherHttpRequestAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnReceivedOtherHttpRequestAsync((TClient)client, e); + } + + #region 虚函数 + + /// + /// + /// + /// + /// + protected virtual void OnDelete(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Delete时 + /// + /// + /// + /// + protected virtual Task OnDeleteAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnGet(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Get时 + /// + /// + /// + /// + protected virtual Task OnGetAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnPost(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Post时 + /// + /// + /// + /// + protected virtual Task OnPostAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnPut(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Put时 + /// + /// + /// + /// + protected virtual Task OnPutAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnReceivedOtherHttpRequest(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到其他Http请求时 + /// + /// + /// + /// + protected virtual Task OnReceivedOtherHttpRequestAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs.meta new file mode 100644 index 0000000..7623dae --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4cc27e73630ab842a3eebbea1c8cb20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs new file mode 100644 index 0000000..8224437 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http静态内容插件 + /// + public class HttpStaticPagePlugin : HttpPluginBase + { + private readonly FileCachePool fileCache; + + /// + /// 构造函数 + /// + public HttpStaticPagePlugin() + { + fileCache = new FileCachePool(); + } + + /// + /// 静态文件缓存。 + /// + public FileCachePool FileCache => fileCache; + + /// + /// 添加静态 + /// + /// Static content path + /// Cache prefix (default is "/") + /// Cache filter (default is "*.*") + /// Refresh cache timeout (default is 1 hour) + public void AddFolder(string path, string prefix = "/", string filter = "*.*", TimeSpan? timeout = null) + { + timeout ??= TimeSpan.FromHours(1); + + fileCache.InsertPath(path, prefix, filter, timeout.Value, null); + } + + /// + /// Clear static content cache + /// + public void ClearFolder() + { + fileCache.Clear(); + } + + /// + /// Remove static content cache + /// + /// Static content path + public void RemoveFolder(string path) + { + fileCache.RemovePath(path); + } + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (fileCache.Find(e.Context.Request.RelativeURL, out byte[] data)) + { + e.Context.Response + .SetStatus() + .SetContentTypeByExtension(Path.GetExtension(e.Context.Request.RelativeURL)) + .SetContentLength(data.Length) + .WriteContent(data); + e.Handled = true; + } + base.OnGet(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs.meta new file mode 100644 index 0000000..422d757 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 275d672973c01e749a55e729b591c66a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets.meta new file mode 100644 index 0000000..38b3842 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d71e47892afe77f439ac0562a6cbd53e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common.meta new file mode 100644 index 0000000..f8efaa6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f819d98def77b1438735dfd9c2bd8f8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs new file mode 100644 index 0000000..14e6b61 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket数据帧 + /// + public class WSDataFrame : IDisposable, IRequestInfo + { + private bool m_disposedValue; + + /// + /// 是否为最后数据帧。 + /// + public bool FIN { get; set; } + + /// + /// 标识RSV-1。 + /// + public bool RSV1 { get; set; } + + /// + /// 标识RSV-2。 + /// + public bool RSV2 { get; set; } + + /// + /// 标识RSV-3。 + /// + public bool RSV3 { get; set; } + + /// + /// 数据类型 + /// + public WSDataType Opcode { get; set; } + + /// + /// 计算掩码 + /// + public bool Mask { get; set; } + + /// + /// 有效载荷数据长度 + /// + public int PayloadLength { get; set; } + + /// + /// 掩码值 + /// + public byte[] MaskingKey { get; set; } + + /// + /// 有效数据 + /// + public ByteBlock PayloadData { get; set; } + + /// + /// 构建数据 + /// + /// + /// + /// + public bool Build(ByteBlock byteBlock, bool masked) + { + if (PayloadData != null) + { + PayloadLength = PayloadData.Len; + } + else + { + PayloadLength = 0; + } + + if (PayloadData == null) + { + return WSTools.Build(byteBlock, this, new byte[0], 0, 0); + } + return WSTools.Build(byteBlock, this, PayloadData.Buffer, 0, PayloadLength); + } + + /// + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!m_disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象) + } + + PayloadData?.Dispose(); + m_disposedValue = true; + } + } + + /// + /// 析构函数 + /// + ~WSDataFrame() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + /// + /// + /// + public void Dispose() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs.meta new file mode 100644 index 0000000..ecb4fb0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3389a8ae70a55b944b9a9bb2914af2f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs new file mode 100644 index 0000000..50a2881 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WSTools + /// + public static class WSTools + { + /// + /// 应答。 + /// + public const string acceptMask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + /// + /// 构建数据 + /// + /// + /// + /// + /// + /// + /// + public static bool Build(ByteBlock byteBlock, WSDataFrame dataFrame, byte[] buffer, int offset, int length) + { + int payloadLength; + + byte[] extLen; + + if (length < 126) + { + payloadLength = length; + extLen = new byte[0]; + } + else if (length < 65536) + { + payloadLength = 126; + extLen = TouchSocketBitConverter.BigEndian.GetBytes((ushort)length); + } + else + { + payloadLength = 127; + extLen = TouchSocketBitConverter.BigEndian.GetBytes((ulong)length); + } + + int header = dataFrame.FIN ? 1 : 0; + header = (header << 1) + (dataFrame.RSV1 ? 1 : 0); + header = (header << 1) + (dataFrame.RSV2 ? 1 : 0); + header = (header << 1) + (dataFrame.RSV3 ? 1 : 0); + header = (header << 4) + (ushort)dataFrame.Opcode; + + if (dataFrame.Mask) + { + header = (header << 1) + 1; + } + else + { + header = (header << 1) + 0; + } + + header = (header << 7) + payloadLength; + + byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)header)); + + if (payloadLength > 125) + { + byteBlock.Write(extLen, 0, extLen.Length); + } + + if (dataFrame.Mask) + { + byteBlock.Write(dataFrame.MaskingKey, 0, 4); + } + + if (payloadLength > 0) + { + if (dataFrame.Mask) + { + if (byteBlock.Capacity < byteBlock.Pos + length) + { + byteBlock.SetCapacity(byteBlock.Pos + length, true); + } + WSTools.DoMask(byteBlock.Buffer, byteBlock.Pos, buffer, offset, length, dataFrame.MaskingKey); + byteBlock.SetLength(byteBlock.Pos + length); + } + else + { + byteBlock.Write(buffer, offset, length); + } + } + return true; + } + + /// + /// 计算Base64值 + /// + /// + /// + public static string CalculateBase64Key(string str) + { + return (str + acceptMask).ToSha1(Encoding.UTF8).ToBase64(); + } + + /// + /// 获取Base64随即字符串。 + /// + /// + public static string CreateBase64Key() + { + var src = new byte[16]; + new Random().NextBytes(src); + return Convert.ToBase64String(src); + } + + /// + /// 掩码运算 + /// + /// + /// + /// + /// + /// + /// + public static void DoMask(byte[] storeBuf, int sOffset, byte[] buffer, int offset, int length, byte[] masks) + { + for (var i = 0; i < length; i++) + { + storeBuf[sOffset + i] = (byte)(buffer[offset + i] ^ masks[i % 4]); + } + } + + /// + /// 获取WS的请求头 + /// + /// + /// + /// + /// + /// + public static HttpRequest GetWSRequest(string host, string url, string version, out string base64Key) + { + HttpRequest request = new HttpRequest + { + Method = "GET", + Protocols = "HTTP", + ProtocolVersion = "1.1" + }; + request.SetUrl(url); + request.SetHeader(HttpHeaders.Host, host); + request.SetHeader(HttpHeaders.Pragma, "no-cache"); + request.SetHeader(HttpHeaders.UserAgent, "TouchSocket.Http.WebSockets"); + request.SetHeader(HttpHeaders.Origin, "RRQM"); + request.SetHeader(HttpHeaders.AcceptEncoding, "deflate, br"); + request.SetHeaderByKey("Connection", "upgrade"); + request.SetHeaderByKey("Upgrade", "websocket"); + request.SetHeaderByKey("Sec-WebSocket-Version", $"{version}"); + base64Key = CreateBase64Key(); + request.SetHeaderByKey("Sec-WebSocket-Key", base64Key); + + return request; + } + + /// + /// 获取响应 + /// + /// + /// + /// + public static bool TryGetResponse(HttpRequest request, HttpResponse response) + { + string upgrade = request.GetHeader(HttpHeaders.Upgrade); + if (string.IsNullOrEmpty(upgrade)) + { + return false; + } + string connection = request.GetHeader(HttpHeaders.Connection); + if (string.IsNullOrEmpty(connection)) + { + return false; + } + string secWebSocketKey = request.GetHeader("sec-websocket-key"); + if (string.IsNullOrEmpty(secWebSocketKey)) + { + return false; + } + + response.StatusCode = "101"; + response.StatusMessage = "switching protocols"; + response.SetHeader(HttpHeaders.Connection, "upgrade"); + response.SetHeader(HttpHeaders.Upgrade, "websocket"); + response.SetHeader("sec-websocket-accept", CalculateBase64Key(secWebSocketKey)); + return true; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs.meta new file mode 100644 index 0000000..b5e03f1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Common/WSTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a97e3bf60b5a8f41a81278b11942d28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components.meta new file mode 100644 index 0000000..286c4bd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5cdc7581f4901b4eb97110867129046 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs new file mode 100644 index 0000000..45f5747 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs @@ -0,0 +1,199 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketClient用户终端简单实现。 + /// + public class WebSocketClient : WebSocketClientBase + { + /// + /// 收到WebSocket数据 + /// + public WSDataFrameEventHandler Received { get; set; } + + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(WSDataFrame dataFrame) + { + Received?.Invoke(this, dataFrame); + base.OnHandleWSDataFrame(dataFrame); + } + } + + /// + /// WebSocket用户终端。 + /// + public class WebSocketClientBase : HttpClientBase, IWebSocketClient + { + /// + /// 请求连接到WebSocket。 + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + return Connect(default, timeout); + } + + /// + /// + /// + /// + /// + /// + public virtual ITcpClient Connect(CancellationToken token, int timeout = 5000) + { + lock (this) + { + if (!Online) + { + base.Connect(timeout); + } + + string base64Key; + IPHost iPHost = Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + string url = iPHost.IsUri ? iPHost.Uri.PathAndQuery : string.Empty; + HttpRequest request = WSTools.GetWSRequest(RemoteIPHost.Host, url, this.GetWebSocketVersion(), out base64Key); + OnHandshaking(new HttpContextEventArgs(new HttpContext(request))); + + var response = Request(request, timeout: timeout, token: token); + if (!response.StatusCode.Trim().Equals("101")) + { + throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response)); + } + string accept = response.GetHeader("sec-websocket-accept").Trim(); + if (accept.IsNullOrEmpty() || !accept.Equals(WSTools.CalculateBase64Key(base64Key).Trim(), StringComparison.OrdinalIgnoreCase)) + { + MainSocket.SafeDispose(); + throw new WebSocketConnectException($"WS服务器返回的应答码不正确,更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response)); + } + + SetAdapter(new WebSocketDataHandlingAdapter()); + SetValue(WebSocketServerPlugin.HandshakedProperty, true); + response.Flag = true; + OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response))); + return this; + } + } + + /// + /// + /// + /// + /// + /// + public Task ConnectAsync(CancellationToken token, int timeout = 5000) + { + return EasyTask.Run(() => + { + return Connect(token, timeout); + }); + } + + #region 事件 + + /// + /// 表示在即将握手连接时。 + /// + public HttpContextEventHandler Handshaking { get; set; } + + /// + /// 表示完成握手后。 + /// + public HttpContextEventHandler Handshaked { get; set; } + + /// + /// 表示在即将握手连接时。 + /// + /// + protected virtual void OnHandshaking(HttpContextEventArgs e) + { + if (UsePlugin && PluginsManager.Raise("OnHandshaking", this, e)) + { + return; + } + Handshaking?.Invoke(this, e); + } + + /// + /// 表示完成握手后。 + /// + /// + protected virtual void OnHandshaked(HttpContextEventArgs e) + { + if (UsePlugin && PluginsManager.Raise("OnHandshaked", this, e)) + { + return; + } + Handshaked?.Invoke(this, e); + } + + #endregion 事件 + + /// + /// 当收到WS数据时。 + /// + /// + protected virtual void OnHandleWSDataFrame(WSDataFrame dataFrame) + { + if (UsePlugin) + { + PluginsManager.Raise("OnHandleWSDataFrame", this, new WSDataFrameEventArgs(dataFrame)); + } + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (this.GetHandshaked()) + { + WSDataFrame dataFrame = (WSDataFrame)requestInfo; + OnHandleWSDataFrame(dataFrame); + } + else + { + if (requestInfo is HttpResponse response) + { + response.Flag = false; + base.HandleReceivedData(byteBlock, requestInfo); + SpinWait.SpinUntil(() => + { + return (bool)response.Flag; + }, 1000); + } + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + SetValue(WebSocketServerPlugin.HandshakedProperty, false); + base.OnDisconnected(e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs.meta new file mode 100644 index 0000000..ca85dc8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec9ffd1ff518bf440947a8bf9ba1ac6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config.meta new file mode 100644 index 0000000..07b2fc9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea88a93af8ce0e34a8e569d1f4b82436 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs new file mode 100644 index 0000000..ac71333 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Http.WebSockets; + +namespace TouchSocket.Sockets +{ + /// + /// WebSocketConfigExtensions + /// + public static class WebSocketConfigExtensions + { + /// + /// 构建WebSocketClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithWebSocketClient(this TouchSocketConfig config) where TClient : IWebSocketClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建WebSocketClient类客户端,并连接 + /// + /// + /// + public static WebSocketClient BuildWithWebSocketClient(this TouchSocketConfig config) + { + return BuildWithWebSocketClient(config); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs.meta new file mode 100644 index 0000000..5806406 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf8d940487f2107458c227160e41aaa6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter.meta new file mode 100644 index 0000000..2a40228 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eec3d036d20bd574caaef899a195b698 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs new file mode 100644 index 0000000..a28222a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs @@ -0,0 +1,290 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket适配器 + /// + public class WebSocketDataHandlingAdapter : DataHandlingAdapter + { + private WSDataFrame m_dataFrameTemp; + + /// + /// 数据包剩余长度 + /// + private int m_surPlusLength = 0; + + /// + /// 临时包 + /// + private ByteBlock m_tempByteBlock; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 解码 + /// + /// + /// + /// + /// + /// + public FilterResult DecodingFromBytes(byte[] dataBuffer, ref int offset, int length, out WSDataFrame dataFrame) + { + int index = offset; + dataFrame = new WSDataFrame(); + dataFrame.RSV1 = dataBuffer[offset].GetBit(6) == 1; + dataFrame.RSV2 = dataBuffer[offset].GetBit(5) == 1; + dataFrame.RSV3 = dataBuffer[offset].GetBit(4) == 1; + dataFrame.FIN = (dataBuffer[offset] >> 7) == 1; + dataFrame.Opcode = (WSDataType)(dataBuffer[offset] & 0xf); + dataFrame.Mask = (dataBuffer[++offset] >> 7) == 1; + + int payloadLength = dataBuffer[offset] & 0x7f; + if (payloadLength < 126) + { + offset++; + } + else if (payloadLength == 126) + { + if (length < 4) + { + offset = index; + return FilterResult.Cache; + } + payloadLength = TouchSocketBitConverter.BigEndian.ToUInt16(dataBuffer, ++offset); + offset += 2; + } + else if (payloadLength == 127) + { + if (length < 12) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, index, length); + offset = index; + return FilterResult.GoOn; + } + payloadLength = (int)TouchSocketBitConverter.BigEndian.ToUInt64(dataBuffer, ++offset); + offset += 8; + } + + dataFrame.PayloadLength = payloadLength; + + if (dataFrame.Mask) + { + if (length < (offset - index) + 4) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, index, length); + offset = index; + return FilterResult.GoOn; + } + dataFrame.MaskingKey = new byte[4]; + dataFrame.MaskingKey[0] = dataBuffer[offset++]; + dataFrame.MaskingKey[1] = dataBuffer[offset++]; + dataFrame.MaskingKey[2] = dataBuffer[offset++]; + dataFrame.MaskingKey[3] = dataBuffer[offset++]; + } + + ByteBlock byteBlock = new ByteBlock(payloadLength); + dataFrame.PayloadData = byteBlock; + + int surlen = length - (offset - index); + if (payloadLength <= surlen) + { + byteBlock.Write(dataBuffer, offset, payloadLength); + offset += payloadLength; + } + else + { + byteBlock.Write(dataBuffer, offset, surlen); + offset += surlen; + } + + return FilterResult.Success; + } + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + + if (m_tempByteBlock != null) + { + m_tempByteBlock.Write(buffer, 0, r); + buffer = m_tempByteBlock.ToArray(); + r = m_tempByteBlock.Pos; + m_tempByteBlock.Dispose(); + m_tempByteBlock = null; + } + + if (m_dataFrameTemp == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (m_surPlusLength == r) + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_dataFrameTemp); + m_dataFrameTemp = null; + m_surPlusLength = 0; + } + else if (m_surPlusLength < r) + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_dataFrameTemp); + m_dataFrameTemp = null; + SplitPackage(buffer, m_surPlusLength, r); + } + else + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, r); + m_surPlusLength -= r; + } + } + } + + /// + /// 当发送数据前处理数据 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + m_tempByteBlock = null; + m_dataFrameTemp = null; + m_surPlusLength = 0; + base.Reset(); + } + + private void PreviewHandle(WSDataFrame dataFrame) + { + try + { + if (dataFrame.Mask) + { + WSTools.DoMask(dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadData.Len, dataFrame.MaskingKey); + } + GoReceived(null, dataFrame); + } + finally + { + dataFrame.Dispose(); + } + } + + /// + /// 分解包 + /// + /// + /// + /// + private void SplitPackage(byte[] dataBuffer, int offset, int length) + { + while (offset < length) + { + if (length - offset < 2) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, offset, length - offset); + return; + } + + switch (DecodingFromBytes(dataBuffer, ref offset, length - offset, out WSDataFrame dataFrame)) + { + case FilterResult.Cache: + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, offset, length - offset); + return; + } + case FilterResult.Success: + { + if (dataFrame.PayloadLength == dataFrame.PayloadData.Len) + { + PreviewHandle(dataFrame); + } + else + { + m_surPlusLength = dataFrame.PayloadLength - dataFrame.PayloadData.Len; + m_dataFrameTemp = dataFrame; + } + } + break; + + case FilterResult.GoOn: + default: + return; + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..f233860 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e121c20166c87a4ca49999f2ad0eac2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs new file mode 100644 index 0000000..5a8cdbf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 收到WebSocket数据 + /// + /// + /// + public delegate void WSDataFrameEventHandler(TClient client, WSDataFrame dataFrame); +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs.meta new file mode 100644 index 0000000..20cc47f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/DelegateCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f2f3bb58cd9a7b47842606641691ac5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum.meta new file mode 100644 index 0000000..d8543a7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d609e73bed03b164dba7c216ee9307e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs new file mode 100644 index 0000000..65a8200 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket数据类型 + /// + public enum WSDataType : ushort + { + /// + /// 表示一个中间数据包,denotes a continuation frame + /// + Cont = 0, + + /// + /// 表示一个text类型数据包 + /// + Text = 1, + + /// + /// 表示一个binary类型数据包 + /// + Binary = 2, + + /// + /// 表示一个断开连接类型数据包 + /// + Close = 8, + + /// + /// 表示一个ping类型数据包 + /// + Ping = 9, + + /// + /// 表示一个pong类型数据包 + /// + Pong = 10 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs.meta new file mode 100644 index 0000000..13d8995 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Enum/WSDataType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1baeaba1a6ff5841b95525ba739407c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs.meta new file mode 100644 index 0000000..7609592 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9ea8e25051ff2854ab64d599d9a5c06b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs new file mode 100644 index 0000000..0dcd0ee --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS数据事件类 + /// + public class WSDataFrameEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public WSDataFrameEventArgs(WSDataFrame dataFrame) + { + DataFrame = dataFrame; + } + + /// + /// WS数据帧。 + /// + public WSDataFrame DataFrame { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs.meta new file mode 100644 index 0000000..dcdf9e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad80f29a27474b64cb1eacb7ba772c47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions.meta new file mode 100644 index 0000000..a805b78 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee39779f7f8c1af4bb930c65a23404fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs new file mode 100644 index 0000000..cf3b84c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket连接异常。 + /// + [Serializable] + public class WebSocketConnectException : Exception + { + /// + ///构造函数 + /// + /// + /// + public WebSocketConnectException(string mes, HttpContext context) : base(mes) + { + Context = context; + } + + /// + /// HttpContext + /// + public HttpContext Context { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs.meta new file mode 100644 index 0000000..d96b7bc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64ede6c1ca789ce44a04408741541cea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions.meta new file mode 100644 index 0000000..f50914e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad8f74062419e814cb699ae6fc1d6338 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs new file mode 100644 index 0000000..8b664ce --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs @@ -0,0 +1,811 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// IWSClientBase辅助扩展 + /// + public static class WSClientExtensions + { + /// + /// 是否已经完成握手 + /// + /// + /// + public static bool GetHandshaked(this IHttpClientBase client) + { + return client.GetValue(WebSocketServerPlugin.HandshakedProperty); + } + + /// + /// 获取WebSocket版本号。 + /// + /// + /// + public static string GetWebSocketVersion(this IHttpClientBase client) + { + return client.GetValue(WebSocketServerPlugin.WebSocketVersionProperty); + } + + /// + /// 设置WebSocket版本号。 + /// + public static void SetWebSocketVersion(this IHttpClientBase client, string value) + { + client.SetValue(WebSocketServerPlugin.WebSocketVersionProperty, value); + } + + #region 客户端 + + /// + /// 发送Ping报文。 + /// + /// + /// + public static bool PingWS(this HttpClientBase client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Pong报文。 + /// + /// + /// + public static bool PongWS(this HttpClientBase client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Close报文。 + /// + /// + /// + /// + public static bool CloseWithWS(this HttpClientBase client, string msg) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg)); + return true; + } + catch + { + return false; + } + } + + #region 同步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, ByteBlock byteBlock) + { + SendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, byte[] buffer) + { + SendWithWS(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, ByteBlock byteBlock) + { + SendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, byte[] buffer) + { + SendWithWSAsync(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 异步发送 + + #region 同步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWS(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.SetMaskString("RRQM"); + dataFrame.Mask = true; + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, byte[] buffer, int packageSize) + { + SubSendWithWS(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 同步分包发送 + + #region 异步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWSAsync(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.SetMaskString("RRQM"); + dataFrame.Mask = true; + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, byte[] buffer, int packageSize) + { + SubSendWithWSAsync(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 异步分包发送 + + #endregion 客户端 + + #region 服务器 + + /// + /// 发送WebSocket协议的Ping报文。 + /// + /// + /// + public static bool PingWS(this HttpSocketClient client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送WebSocket协议的Pong报文。 + /// + /// + /// + public static bool PongWS(this HttpSocketClient client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送WebSocket协议的Close报文。 + /// + /// + /// + /// + public static bool CloseWithWS(this HttpSocketClient client, string msg) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg)); + return true; + } + catch + { + return false; + } + } + + #region 同步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, ByteBlock byteBlock) + { + SendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, byte[] buffer) + { + SendWithWS(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, ByteBlock byteBlock) + { + SendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, byte[] buffer) + { + SendWithWSAsync(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 异步发送 + + #region 同步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWS(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, byte[] buffer, int packageSize) + { + SubSendWithWS(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 同步分包发送 + + #region 异步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWSAsync(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, byte[] buffer, int packageSize) + { + SubSendWithWSAsync(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 异步分包发送 + + #endregion 服务器 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs.meta new file mode 100644 index 0000000..c4d3556 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd49377316861654faa98fb7ba6be17f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs new file mode 100644 index 0000000..7a37f4b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WSDataFrame辅助扩展类 + /// + public static class WSDataFrameExtensions + { + /// + /// 追加文本 + /// + /// + /// + /// + /// + public static WSDataFrame AppendText(this WSDataFrame dataFrame, string text, Encoding encoding = default) + { + dataFrame.Opcode = WSDataType.Text; + byte[] data = (encoding == default ? Encoding.UTF8 : encoding).GetBytes(text); + if (dataFrame.PayloadData == null) + { + dataFrame.PayloadData = new ByteBlock(); + } + dataFrame.PayloadData.Write(data); + return dataFrame; + } + + /// + /// 追加二进制流 + /// + /// + /// + /// + /// + /// + public static WSDataFrame AppendBinary(this WSDataFrame dataFrame, byte[] buffer, int offset, int length) + { + dataFrame.Opcode = WSDataType.Binary; + if (dataFrame.PayloadData == null) + { + dataFrame.PayloadData = new ByteBlock(); + } + dataFrame.PayloadData.Write(buffer, offset, length); + return dataFrame; + } + + /// + /// 构建请求数据(含Make) + /// + /// + /// + /// + public static bool BuildRequest(this WSDataFrame dataFrame, ByteBlock byteBlock) + { + dataFrame.FIN = true; + dataFrame.Mask = true; + if (dataFrame.MaskingKey == null) + { + dataFrame.SetMaskString("RRQM"); + } + return dataFrame.Build(byteBlock, true); + } + + /// + /// 构建请求数据(含Make) + /// + /// + /// + public static byte[] BuildRequestToBytes(this WSDataFrame dataFrame) + { + dataFrame.FIN = true; + dataFrame.Mask = true; + if (dataFrame.MaskingKey == null) + { + dataFrame.SetMaskString("RRQM"); + } + using (ByteBlock byteBlock = new ByteBlock()) + { + dataFrame.Build(byteBlock, true); + byte[] data = byteBlock.ToArray(); + return data; + } + } + + /// + /// 构建响应数据(无Make) + /// + /// + /// + /// + public static bool BuildResponse(this WSDataFrame dataFrame, ByteBlock byteBlock) + { + dataFrame.FIN = true; + + return dataFrame.Build(byteBlock, false); + } + + /// + /// 构建响应数据(无Make) + /// + /// + /// + public static byte[] BuildResponseToBytes(this WSDataFrame dataFrame) + { + dataFrame.FIN = true; + + using (ByteBlock byteBlock = new ByteBlock()) + { + dataFrame.Build(byteBlock, false); + byte[] data = byteBlock.ToArray(); + return data; + } + } + + /// + /// 设置Mask。 + /// + /// + /// + /// + public static WSDataFrame SetMaskString(this WSDataFrame dataFrame, string mask) + { + byte[] masks = Encoding.UTF8.GetBytes(mask); + if (masks.Length != 4) + { + throw new OverlengthException("Mask只能为ASCII,且只能为四位。"); + } + dataFrame.MaskingKey = masks; + return dataFrame; + } + + /// + /// 当时,转换为Text消息。 + /// + /// + /// + /// + public static string ToText(this WSDataFrame dataFrame, Encoding encoding = default) + { + return (encoding == default ? Encoding.UTF8 : encoding).GetString(dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadLength); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs.meta new file mode 100644 index 0000000..b4cc094 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8bdb00c19eedd9045b1d951b4861d9af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs new file mode 100644 index 0000000..51537dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketExtensions + /// + public static class WebSocketExtensions + { + /// + /// 心跳Timer + /// + public static readonly DependencyProperty HeartbeatTimerProperty = + DependencyProperty.Register("HeartbeatTimer", typeof(WebSocketExtensions), null); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs.meta new file mode 100644 index 0000000..0e6a747 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15fbd884ff4463f429dff59747b39f11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs new file mode 100644 index 0000000..f62d6db --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http.WebSockets; + +namespace TouchSocket.Core +{ + /// + /// WebSocketPluginsManagerExtension + /// + public static class WebSocketPluginsManagerExtension + { + /// + /// 使用WebSocket插件 + /// + /// 插件类型实例 + public static WebSocketServerPlugin UseWebSocket(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + + /// + /// 使用WebSocket心跳插件(仅客户端生效) + /// + /// 插件类型实例 + public static WebSocketHeartbeatPlugin UseWebSocketHeartbeat(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..e4cee5f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18c05db7166cdfa44a6edbbbdf5dcb0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs new file mode 100644 index 0000000..395716f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketServerExtensions + /// + public static class WebSocketServerExtensions + { + /// + /// 转化Protocol协议标识为 + /// + /// + /// Http上下文 + public static bool SwitchProtocolToWebSocket(this TClient client, HttpContext httpContext) where TClient : HttpSocketClient + { + if (client.Protocol == Protocol.WebSocket) + { + return true; + } + if (client.Protocol == Protocol.Http) + { + if (WSTools.TryGetResponse(httpContext.Request, httpContext.Response)) + { + HttpContextEventArgs args = new HttpContextEventArgs(new HttpContext(httpContext.Request, httpContext.Response)) + { + IsPermitOperation = true + }; + client.PluginsManager.Raise(nameof(IWebSocketPlugin.OnHandshaking), client, args); + if (args.Context.Response.Responsed) + { + return false; + } + if (args.IsPermitOperation) + { + client.SetDataHandlingAdapter(new WebSocketDataHandlingAdapter()); + client.Protocol = Protocol.WebSocket; + client.SetValue(WebSocketServerPlugin.HandshakedProperty, true);//设置握手状态 + + using (ByteBlock byteBlock = new ByteBlock()) + { + args.Context.Response.Build(byteBlock); + client.DefaultSend(byteBlock); + } + client.PluginsManager.Raise(nameof(IWebSocketPlugin.OnHandshaked), client, new HttpContextEventArgs(httpContext)); + return true; + } + else + { + args.Context.Response.SetStatus("403", "Forbidden"); + using (ByteBlock byteBlock = new ByteBlock()) + { + args.Context.Response.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + client.Close("主动拒绝WebSocket连接"); + } + } + else + { + client.Close("WebSocket连接协议不正确"); + } + } + return false; + } + + /// + /// 转化Protocol协议标识为 + /// + /// + /// Http上下文 + public static Task SwitchProtocolToWebSocketAsync(this TClient client, HttpContext httpContext) where TClient : HttpSocketClient + { + return EasyTask.Run(() => + { + return SwitchProtocolToWebSocket(client, httpContext); + }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs.meta new file mode 100644 index 0000000..b6a8d63 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4da7cba4696b4114ebccbaff55e729b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface.meta new file mode 100644 index 0000000..4c5f00f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 608c6b5cc75976545a5ca55690247e88 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs new file mode 100644 index 0000000..d855c9b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 用户终端接口 + /// + public interface IWebSocketClient : IHttpClient + { + /// + /// 连接到ws服务器 + /// + /// + /// + /// + ITcpClient Connect(CancellationToken token, int timeout = 5000); + + /// + /// 异步连接到ws服务器 + /// + /// + /// + /// + Task ConnectAsync(CancellationToken token, int timeout = 5000); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs.meta new file mode 100644 index 0000000..f107859 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 192a7d93ae5586e4995b8778689b3106 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs new file mode 100644 index 0000000..787a324 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket插件 + /// + public interface IWebSocketPlugin : IPlugin + { + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + [AsyncRaiser] + void OnClosing(ITcpClientBase client, MsgEventArgs e); + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + Task OnClosingAsync(ITcpClientBase client, MsgEventArgs e); + + /// + /// 当收到WS数据时。 + /// + /// + /// + [AsyncRaiser] + void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e); + + /// + /// 当收到WS数据时。 + /// + /// + /// + /// + Task OnHandleWSDataFrameAsync(ITcpClientBase client, WSDataFrameEventArgs e); + + /// + /// 表示完成握手后。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示完成握手后。 + /// + /// + /// + /// + Task OnHandshakedAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaking(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + /// + Task OnHandshakingAsync(ITcpClientBase client, HttpContextEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs.meta new file mode 100644 index 0000000..d88b725 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 208936cf169fbc34692ba8aeae2518d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins.meta new file mode 100644 index 0000000..a54addd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aff411d1fc772ea45989982de10bbd6f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs new file mode 100644 index 0000000..3aff937 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS命令行插件。 + /// + public abstract class WSCommandLinePlugin : WebSocketPluginBase + { + private readonly Dictionary pairs = new Dictionary(); + private readonly ILog m_logger; + + /// + /// 字符串转换器,默认支持基础类型和Json。可以自定义。 + /// + public StringConverter Converter { get; } + + /// + /// 是否返回执行异常。 + /// + public bool ReturnException { get; set; } = true; + + /// + /// 当有执行异常时,不返回异常。 + /// + /// + public WSCommandLinePlugin NoReturnException() + { + ReturnException = false; + return this; + } + + /// + /// WSCommandLinePlugin + /// + /// + /// + protected WSCommandLinePlugin(ILog logger) + { + m_logger = logger ?? throw new ArgumentNullException(nameof(logger)); + Converter = new StringConverter(); + var ms = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(a => a.Name.EndsWith("Command")); + foreach (var item in ms) + { + pairs.Add(item.Name.Replace("Command", string.Empty), new Method(item)); + } + } + + /// + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Text) + { + try + { + string[] strs = e.DataFrame.ToText().Split(' '); + if (strs.Length > 0 && pairs.TryGetValue(strs[0], out Method method)) + { + var ps = method.Info.GetParameters(); + object[] os = new object[ps.Length]; + int index = 0; + for (int i = 0; i < ps.Length; i++) + { + if (ps[i].ParameterType.IsInterface && typeof(ITcpClientBase).IsAssignableFrom(ps[i].ParameterType)) + { + os[i] = client; + } + else + { + os[i] = Converter.ConvertFrom(strs[index + 1], ps[i].ParameterType); + index++; + } + } + + e.Handled = true; + + try + { + object result = method.Invoke(this, os); + if (method.HasReturn) + { + if (client is HttpClient httpClient) + { + httpClient.SendWithWS(Converter.ConvertTo(result)); + } + else if (client is HttpSocketClient httpSocketClient) + { + httpSocketClient.SendWithWS(Converter.ConvertTo(result)); + } + } + } + catch (Exception ex) + { + if (ReturnException) + { + if (client is HttpClient httpClient) + { + httpClient.SendWithWS(Converter.ConvertTo(ex.Message)); + } + else if (client is HttpSocketClient httpSocketClient) + { + httpSocketClient.SendWithWS(Converter.ConvertTo(ex.Message)); + } + } + } + } + } + catch (Exception ex) + { + m_logger.Exception(this, ex); + } + } + + base.OnHandleWSDataFrame(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs.meta new file mode 100644 index 0000000..97ad2e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad667c4e41738b54090626d3fa25bdc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs new file mode 100644 index 0000000..6e104ed --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketHeartbeatPlugin + /// + [SingletonPlugin] + public class WebSocketHeartbeatPlugin : WebSocketPluginBase + { + private TimeSpan m_timeTick=TimeSpan.FromSeconds(5); + + /// + /// 初始化一个适用于WebSocket的心跳插件 + /// + public WebSocketHeartbeatPlugin() + { + + } + + /// + /// 设置心跳间隔,默认5秒。 + /// + /// + public void Tick(TimeSpan timeSpan) + { + this.m_timeTick = timeSpan; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e) + { + if (client is HttpClientBase httpClientBase) + { + if (client.GetValue(WebSocketExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + } + client.SetValue(WebSocketExtensions.HeartbeatTimerProperty, new Timer((o) => + { + httpClientBase.PingWS(); + }, null, m_timeTick, m_timeTick)); + } + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + base.OnDisconnected(client, e); + if (client.GetValue(WebSocketExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.SafeDispose(); + client.SetValue(WebSocketExtensions.HeartbeatTimerProperty, null); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs.meta new file mode 100644 index 0000000..2321507 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e957c258f834c44781336748a4e3d9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs new file mode 100644 index 0000000..2420a06 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS插件基类 + /// + public class WebSocketPluginBase : WebSocketPluginBase + { + } + + /// + /// WS插件基类 + /// + public class WebSocketPluginBase : HttpPluginBase, IWebSocketPlugin + { + #region 虚函数 + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + protected virtual void OnClosing(ITcpClientBase client, MsgEventArgs e) + { + } + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + /// + protected virtual Task OnClosingAsync(ITcpClientBase client, MsgEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 处理WS数据帧。 + /// + /// + /// + protected virtual void OnHandleWSDataFrame(TClient client, WSDataFrameEventArgs e) + { + } + + /// + /// 处理WS数据帧。 + /// + /// + /// + /// + protected virtual Task OnHandleWSDataFrameAsync(TClient client, WSDataFrameEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 表示完成握手后。 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 表示完成握手后。 + /// + /// + /// + /// + protected virtual Task OnHandshakedAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 表示在即将握手连接时。 + /// 在此处拒绝操作,则会返回403 Forbidden。 + /// 也可以向注入更多信息。 + /// + /// + /// + protected virtual void OnHandshaking(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + /// + protected virtual Task OnHandshakingAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + + void IWebSocketPlugin.OnClosing(ITcpClientBase client, MsgEventArgs e) + { + OnClosing(client, e); + } + + Task IWebSocketPlugin.OnClosingAsync(ITcpClientBase client, MsgEventArgs e) + { + return OnClosingAsync(client, e); + } + + void IWebSocketPlugin.OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + OnHandleWSDataFrame((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandleWSDataFrameAsync(ITcpClientBase client, WSDataFrameEventArgs e) + { + return OnHandleWSDataFrameAsync((TClient)client, e); + } + + void IWebSocketPlugin.OnHandshaked(ITcpClientBase client, HttpContextEventArgs e) + { + OnHandshaked((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandshakedAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnHandshakedAsync((TClient)client, e); + } + + void IWebSocketPlugin.OnHandshaking(ITcpClientBase client, HttpContextEventArgs e) + { + OnHandshaking((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandshakingAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnHandshakingAsync((TClient)client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs.meta new file mode 100644 index 0000000..24dd997 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 004c2eb227075b149a01d3c492f21a74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs new file mode 100644 index 0000000..84c90a9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 基于Http的WebSocket的扩展。 + /// 此组件只能挂载在 + /// + [SingletonPlugin] + public class WebSocketServerPlugin : HttpPluginBase + { + /// + /// 表示是否完成WS握手 + /// + public static readonly DependencyProperty HandshakedProperty = + DependencyProperty.Register("Handshaked", typeof(WebSocketServerPlugin), false); + + /// + /// 表示WebSocketVersion + /// + public static readonly DependencyProperty WebSocketVersionProperty = + DependencyProperty.Register("WebSocketVersion", typeof(WebSocketServerPlugin), "13"); + + private readonly IPluginsManager m_pluginsManager; + + private string m_wSUrl = "/ws"; + + /// + /// WebSocketServerPlugin + /// + /// + public WebSocketServerPlugin(IPluginsManager pluginsManager) + { + m_pluginsManager = pluginsManager ?? throw new ArgumentNullException(nameof(pluginsManager)); + } + + /// + /// 是否默认处理Close报文。 + /// + public bool AutoClose { get; set; } = true; + + /// + /// 当收到ping报文时,是否自动回应pong。 + /// + public bool AutoPong { get; set; } + + /// + /// 处理WS数据的回调 + /// + public Action HandleWSDataFrameCallback { get; set; } + + /// + /// 用于WebSocket连接的路径,默认为“/ws” + /// 如果设置为null或空,则意味着所有的连接都将解释为WS + /// + public string WSUrl + { + get => m_wSUrl; + set => m_wSUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + /// + /// 不处理Close报文。 + /// + /// + public WebSocketServerPlugin NoAutoClose() + { + AutoClose = false; + return this; + } + + /// + /// 当收到ping报文时,自动回应pong。 + /// + /// + public WebSocketServerPlugin UseAutoPong() + { + AutoPong = true; + return this; + } + + /// + /// 设置处理WS数据的回调。 + /// + /// + public WebSocketServerPlugin SetCallback(Action action) + { + HandleWSDataFrameCallback = action; + return this; + } + + /// + /// 用于WebSocket连接的路径,默认为“/ws” + /// 如果设置为null或空,则意味着所有的连接都将解释为WS + /// + /// + /// + public WebSocketServerPlugin SetWSUrl(string url) + { + WSUrl = url; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (WSUrl == "/" || e.Context.Request.UrlEquals(WSUrl)) + { + if (client.Protocol == Protocol.Http) + { + e.Handled = true; + if (client is HttpSocketClient socketClient) + { + socketClient.SwitchProtocolToWebSocket(e.Context); + } + } + } + base.OnGet(client, e); + } + + /// + /// 处理WS数据帧。覆盖父类方法将不会触发回调和插件。 + /// + /// + /// + protected virtual void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (AutoClose&&e.DataFrame.Opcode == WSDataType.Close) + { + string msg = e.DataFrame.PayloadData?.ToString(); + m_pluginsManager.Raise(nameof(IWebSocketPlugin.OnClosing), client, new MsgEventArgs() { Message = msg }); + client.Close(msg); + return; + } + if (AutoPong&& e.DataFrame.Opcode == WSDataType.Ping) + { + ((HttpSocketClient)client).PongWS(); + return; + } + if (m_pluginsManager.Raise(nameof(IWebSocketPlugin.OnHandleWSDataFrame), client, e)) + { + return; + } + HandleWSDataFrameCallback?.Invoke(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (client.Protocol == Protocol.WebSocket) + { + if (e.RequestInfo is WSDataFrame dataFrame) + { + e.Handled = true; + OnHandleWSDataFrame(client, new WSDataFrameEventArgs(dataFrame)); + } + } + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs.meta new file mode 100644 index 0000000..7f5710f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c925d49f827deb345b56c18b77a64b5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources.meta new file mode 100644 index 0000000..eee1553 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53ee39f417893e446bc373880b26c5e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs new file mode 100644 index 0000000..04b334a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Runtime.CompilerServices; + +#if NET6_0_OR_GREATER +#else +[assembly: SuppressIldasm()] +#endif diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs.meta new file mode 100644 index 0000000..c3e1ab5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b99720b07c9ea174aa9b291b3b916e20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs new file mode 100644 index 0000000..7406387 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs @@ -0,0 +1,251 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.ComponentModel; + +namespace TouchSocket.Resources +{ + /// + /// TouchSocket资源枚举 + /// + public enum TouchSocketStatus : byte + { + /// + /// 未知错误 + /// + [Description("未知错误")] + UnknownError, + + /// + /// 操作成功 + /// + [Description("操作成功")] + Success, + + /// + /// 操作超时 + /// + [Description("操作超时")] + Overtime, + + /// + /// 用户主动取消操作。 + /// + [Description("用户主动取消操作。")] + Canceled, + + /// + /// 参数‘{0}’为空。 + /// + [Description("参数‘{0}’为空。")] + ArgumentNull, + + /// + ///发生异常,信息:{0}。 + /// + [Description("发生异常,信息:{0}。")] + Exception, + + #region TouchRpc + + /// + /// 不允许路由该包,信息:{0}。 + /// + [Description("不允许路由该包,信息:{0}。")] + RoutingNotAllowed, + + /// + /// 未找到该公共方法,或该方法未标记为Rpc + /// + [Description("未找到该公共方法,或该方法未标记为Rpc")] + RpcMethodNotFind, + + /// + /// 方法已被禁用 + /// + [Description("方法已被禁用")] + RpcMethodDisable, + + /// + /// 函数执行异常,详细信息:{0} + /// + [Description("函数执行异常,详细信息:{0}")] + RpcInvokeException, + + /// + /// 事件操作器异常 + /// + [Description("事件操作器异常。")] + GetEventArgsFail, + + /// + /// 通道设置失败。 + /// + [Description("通道设置失败。")] + SetChannelFail, + + /// + /// ID为{0}的通道已存在。 + /// + [Description("ID为{0}的通道已存在。")] + ChannelExisted, + + /// + /// 远程终端拒绝该操作,反馈信息:{0}。 + /// + [Description("远程终端拒绝该操作,反馈信息:{0}。")] + RemoteRefuse, + + /// + /// 从‘{0}’创建写入流失败,信息:{1}。" + /// + [Description("从‘{0}’创建写入流失败,信息:{1}。")] + CreateWriteStreamFail, + + /// + ///没有找到路径‘{0}’对应的流文件。 + /// + [Description("没有找到路径‘{0}’对应的流文件。")] + StreamNotFind, + + /// + /// 没有找到ID为{0}的客户端。 + /// + [Description("没有找到ID为{0}的客户端。")] + ClientNotFind, + + /// + /// 路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。 + /// + [Description("路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。")] + StreamReferencing, + + /// + /// 接收流容器为空 + /// + [Description("流容器为空。")] + StreamBucketNull, + + /// + /// 从‘{0}’路径加载流异常,信息:‘{1}’。 + /// + [Description("从‘{0}’路径加载流异常,信息:‘{1}’。")] + LoadStreamFail, + + /// + /// 目录‘{0}’已存在。 + /// + [Description("目录‘{0}’已存在。")] + DirectoryExisted, + + /// + /// 文件‘{0}’已存在。 + /// + [Description("文件‘{0}’已存在。")] + FileExisted, + + /// + /// 文件‘{0}’不存在。 + /// + [Description("文件‘{0}’不存在。")] + FileNotExists, + + /// + /// 目录‘{0}’不存在。 + /// + [Description("目录‘{0}’不存在。")] + DirectoryNotExists, + + /// + /// 名称为“{0}”的事件已存在 + /// + [Description("名称为“{0}”的事件已存在。")] + EventExisted, + + /// + /// 名称为“{0}”的事件不存在 + /// + [Description("名称为“{0}”的事件不存在。")] + EventNotExist, + + /// + /// 资源句柄{0}对应的资源没有找到,可能操作已超时。 + /// + [Description("资源句柄{0}对应的资源没有找到,可能操作已超时。")] + ResourceHandleNotFind, + + /// + /// 还有{0}个资源没有完成。 + /// + [Description("还有{0}个资源没有完成。")] + HasUnFinished, + + /// + /// 文件长度太长。 + /// + [Description("文件长度太长。")] + FileLengthTooLong, + + /// + /// 读取文件长度错误。 + /// + [Description("读取文件长度错误。")] + LengthErrorWhenRead, + + /// + /// 没有找到任何可用的目标Id。 + /// + [Description("没有找到任何可用的目标Id。")] + NotFindAnyTargetId, + + #endregion TouchRpc + + #region Core + + /// + /// Token消息为‘{0}’的已注册。 + /// + [Description("Token消息为‘{0}’的已注册。")] + TokenExisted, + + /// + /// Token消息为‘{0}’的未注册。 + /// + [Description("Token消息为‘{0}’的未注册。")] + MessageNotFound, + + #endregion Core + + #region Client + + /// + /// 数据处理适配器为空,可能客户端已掉线。 + /// + [Description("数据处理适配器为空,可能客户端已掉线。")] + NullDataAdapter, + + /// + /// 客户端没有连接 + /// + [Description("客户端没有连接。")] + NotConnected, + + /// + /// 授权密钥无效,程序将在5秒后退出。请检查密钥,或者不使用企业版功能。 + /// + [Description("授权密钥无效,程序将在5秒后退出。请检查密钥,或者不使用企业版功能。")] + LicenceKeyInvalid, + + #endregion Client + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs.meta new file mode 100644 index 0000000..493eb07 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f9cdb5ca0a0d774b81ceaa9f385dafe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs new file mode 100644 index 0000000..d0a9b24 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Resources +{ + /// + /// StatusExtension + /// + internal static class TouchSocketStatusExtension + { + /// + /// 转为状态字 + /// + /// + /// + public static TouchSocketStatus ToStatus(this byte value) + { + return (TouchSocketStatus)value; + } + + /// + /// 转为数值 + /// + /// + /// + public static byte ToValue(this TouchSocketStatus value) + { + return (byte)value; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs.meta new file mode 100644 index 0000000..639dc4b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Resources/TouchSocketStatusExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac5d347652e72ff47b3963cfc32778a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc.meta new file mode 100644 index 0000000..f765fe2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e31a28d7fce7e04386939f8f3b37cc8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global.meta new file mode 100644 index 0000000..d1abedd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f5f5ba82ec8d594ba41078e9b0df791 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute.meta new file mode 100644 index 0000000..bb40f1a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5e2d5f9d44d6ca409d36d0e7312f925 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs new file mode 100644 index 0000000..5cc5697 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Rpc +{ + /// + /// RPC行为过滤器。 + /// + public interface IRpcActionFilter + { + /// + /// 成功执行Rpc后。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + void Executed(ICallContext callContext,object[] parameters, ref InvokeResult invokeResult); + + /// + /// 成功执行Rpc后。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + Task ExecutedAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + + /// + /// 执行Rpc遇见异常。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + /// + void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception); + + /// + /// 执行Rpc遇见异常。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + /// + Task ExecutExceptionAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception); + + /// + /// 在执行Rpc之前。 + /// 的InvokeStatus不为。则不会执行RPC + /// 同时,当的InvokeStatus为。会直接返回结果 + /// + /// + /// + /// + void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + + /// + /// 在执行Rpc之前。 + /// 的InvokeStatus不为。则不会执行RPC + /// 同时,当的InvokeStatus为。会直接返回结果 + /// + /// + /// + /// + Task ExecutingAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs.meta new file mode 100644 index 0000000..ffc3a90 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ebad73425aa9193498a342366652a76b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs new file mode 100644 index 0000000..70b7d66 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// RpcActionFilterAttribute + /// + public abstract class RpcActionFilterAttribute : Attribute, IRpcActionFilter + { + /// + public virtual void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + } + + /// + public virtual Task ExecutedAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + return EasyTask.CompletedTask; + } + + /// + public virtual void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) + { + } + + /// + public virtual Task ExecutExceptionAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) + { + return EasyTask.CompletedTask; + } + + /// + public virtual void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + } + + /// + public virtual Task ExecutingAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + return EasyTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs.meta new file mode 100644 index 0000000..e622248 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: db3600fd2917d0e44855434959441c8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs new file mode 100644 index 0000000..5dd6f2e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs @@ -0,0 +1,902 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc方法属性基类 + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + public abstract class RpcAttribute : Attribute + { + private readonly Dictionary m_exceptions = new Dictionary(); + + /// + /// 构造函数 + /// + public RpcAttribute() + { + MethodFlags = MethodFlags.None; + m_exceptions.Add(typeof(TimeoutException), "调用超时"); + m_exceptions.Add(typeof(RpcInvokeException), "Rpc调用异常"); + m_exceptions.Add(typeof(Exception), "其他异常"); + } + + /// + /// 类生成器 + /// + public ClassCodeGenerator ClassCodeGenerator { get; private set; } + + /// + /// 异常提示 + /// + public Dictionary Exceptions => m_exceptions; + + /// + /// 生成代码 + /// + public CodeGeneratorFlag GeneratorFlag { get; set; } = + CodeGeneratorFlag.InstanceSync | CodeGeneratorFlag.InstanceAsync | CodeGeneratorFlag.ExtensionSync | CodeGeneratorFlag.ExtensionAsync + | CodeGeneratorFlag.InterfaceSync | CodeGeneratorFlag.InterfaceAsync; + + /// + /// 生成泛型方法的约束 + /// + public Type[] GenericConstraintTypes { get; set; } = new Type[] { typeof(IRpcClient) }; + + /// + /// 调用键。 + /// + public string InvokeKey { get; set; } + + /// + /// 函数标识 + /// + public MethodFlags MethodFlags { get; set; } + + /// + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + public bool MethodInvoke { get; set; } + + /// + /// 重新指定生成的函数名称。可以使用类似“JsonRpc_{0}”的模板格式。 + /// + public string MethodName { get; set; } + + /// + /// 当使用TryCanInvoke不能调用时,执行的代码。 + /// + /// + public virtual string GetCannotInvoke(MethodInstance methodInstance) + { + return "throw new RpcException(\"Rpc无法执行。\");"; + } + + /// + /// 获取注释信息 + /// + /// + /// + public virtual string GetDescription(MethodInstance methodInstance) + { + return string.IsNullOrEmpty(methodInstance.GetDescription()) ? "无注释信息" : methodInstance.GetDescription(); + } + + /// + /// 获取扩展的代理代码 + /// + /// + /// + public virtual string GetExtensionsMethodProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + + string description = GetDescription(methodInstance); + + List parametersStr = GetParameters(methodInstance, out bool isOut, out bool isRef, out ParameterInfo[] parameters); + var InterfaceTypes = GetGenericConstraintTypes(); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append("public static "); + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + + codeString.Append($"this TClient client"); + + codeString.Append(","); + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(") where TClient:"); + + for (int i = 0; i < InterfaceTypes.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(InterfaceTypes[i].FullName); + } + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if (client.TryCanInvoke?.Invoke(client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine(GetCannotInvoke(methodInstance)); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + + foreach (ParameterInfo parameter in parameters) + { + if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) + { + codeString.Append($"default({GetProxyParameterName(parameter)})"); + } + else + { + codeString.Append(parameter.Name); + } + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + + if (isOut || isRef) + { + codeString.Append($"Type[] types = new Type[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append($"typeof({GetProxyParameterName(parameter)})"); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + if (isOut || isRef) + { + codeString.AppendLine("if(parameters!=null)"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, GetProxyParameterName(parameters[i]), i)); + } + codeString.AppendLine("}"); + if (isOut) + { + codeString.AppendLine("else"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].IsOut) + { + codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, GetProxyParameterName(parameters[i]))); + } + } + codeString.AppendLine("}"); + } + } + + if (methodInstance.HasReturn) + { + codeString.AppendLine("return returnData;"); + } + + codeString.AppendLine("}"); + } + + //以下生成异步 + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + codeString.Append("public static "); + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + codeString.Append($"this TClient client"); + + codeString.Append(","); + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(") where TClient:"); + + for (int i = 0; i < InterfaceTypes.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(InterfaceTypes[i].FullName); + } + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if (client.TryCanInvoke?.Invoke(client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append(parameter.Name); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("return client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append(string.Format("return client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("return client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append("return client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + codeString.AppendLine("}"); + } + return codeString.ToString(); + } + + /// + /// 获取生成的函数泛型限定名称。默认 + /// + /// + public virtual Type[] GetGenericConstraintTypes() + { + return GenericConstraintTypes; + } + + /// + /// 获取生成实体类时的代码块 + /// + /// + /// + public virtual string GetInstanceProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + + string description = GetDescription(methodInstance); + ParameterInfo[] parameters; + bool isOut; + bool isRef; + List parametersStr = GetParameters(methodInstance, out isOut, out isRef, out parameters); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceSync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append("public "); + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(")"); + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + + foreach (ParameterInfo parameter in parameters) + { + if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) + { + codeString.Append($"default({GetProxyParameterName(parameter)})"); + } + else + { + codeString.Append(parameter.Name); + } + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + + if (isOut || isRef) + { + codeString.Append($"Type[] types = new Type[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append($"typeof({GetProxyParameterName(parameter)})"); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + if (isOut || isRef) + { + codeString.AppendLine("if(parameters!=null)"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, GetProxyParameterName(parameters[i]), i)); + } + codeString.AppendLine("}"); + if (isOut) + { + codeString.AppendLine("else"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].IsOut) + { + codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, GetProxyParameterName(parameters[i]))); + } + } + codeString.AppendLine("}"); + } + } + + if (methodInstance.HasReturn) + { + codeString.AppendLine("return returnData;"); + } + + codeString.AppendLine("}"); + } + + //以下生成异步 + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + codeString.Append("public "); + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(")"); + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + + codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append(parameter.Name); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("return Client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append(string.Format("return Client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("return Client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append("return Client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + codeString.AppendLine("}"); + } + return codeString.ToString(); + } + + /// + /// 获取接口的代理代码 + /// + /// + /// + public virtual string GetInterfaceProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + bool isOut = false; + bool isRef = false; + string description = GetDescription(methodInstance); + List parameters = GetParameters(methodInstance, out isOut, out isRef, out _); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceSync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + for (int i = 0; i < parameters.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parameters[i]); + } + if (parameters.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(");"); + } + + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parameters.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parameters[i]); + } + if (parameters.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(");"); + } + + return codeString.ToString(); + } + + /// + /// 获取调用键 + /// + /// + /// + public virtual string GetInvokenKey(MethodInstance methodInstance) + { + if (MethodInvoke) + { + return GetMethodName(methodInstance, false); + } + else + { + if (!InvokeKey.IsNullOrEmpty()) + { + return InvokeKey; + } + return $"{methodInstance.ServerType.FullName}.{methodInstance.Name}".ToLower(); + } + } + + /// + /// 获取调用配置 + /// + /// + public virtual string GetInvokeOption() + { + return "IInvokeOption invokeOption = default"; + } + + /// + /// 获取生成的函数名称 + /// + /// + /// + /// + public virtual string GetMethodName(MethodInstance methodInstance, bool isAsync) + { + string name; + if (string.IsNullOrEmpty(MethodName)) + { + name = methodInstance.Name; + } + else + { + name = MethodName.Format(methodInstance.Name); + } + return isAsync ? name + "Async" : name; + } + + /// + /// 获取参数生成 + /// + /// + /// + /// + /// + /// + public virtual List GetParameters(MethodInstance methodInstance, out bool isOut, out bool isRef, out ParameterInfo[] parameters) + { + List list = new List(); + isOut = false; + isRef = false; + + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + List infos = new List(methodInstance.Parameters); + infos.RemoveAt(0); + parameters = infos.ToArray(); + } + else + { + parameters = methodInstance.Parameters; + } + + for (int i = 0; i < parameters.Length; i++) + { + StringBuilder codeString = new StringBuilder(); + if (parameters[i].ParameterType.Name.Contains("&")) + { + if (parameters[i].IsOut) + { + isOut = true; + codeString.Append(string.Format("out {0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + else + { + isRef = true; + codeString.Append(string.Format("ref {0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + } + else + { + codeString.Append(string.Format("{0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + + if (parameters[i].HasDefaultValue) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (defaultValue.GetType() == typeof(bool)) + { + codeString.Append(string.Format("={0}", defaultValue.ToString().ToLower())); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + + list.Add(codeString.ToString()); + } + + return list; + } + + /// + /// 从类型获取代理名 + /// + /// + /// + public virtual string GetProxyParameterName(ParameterInfo parameterInfo) + { + return ClassCodeGenerator.GetTypeFullName(parameterInfo); + } + + /// + /// 获取返回值 + /// + /// + /// + /// + public virtual string GetReturn(MethodInstance methodInstance, bool isAsync) + { + if (isAsync) + { + if (methodInstance.ReturnType == null) + { + return "Task"; + } + else + { + return $"Task<{GetProxyParameterName(methodInstance.Info.ReturnParameter)}>"; + } + } + else + { + if (methodInstance.ReturnType == null) + { + return "void"; + } + else + { + return GetProxyParameterName(methodInstance.Info.ReturnParameter); + } + } + } + + internal void SetClassCodeGenerator(ClassCodeGenerator classCodeGenerator) + { + ClassCodeGenerator = classCodeGenerator; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs.meta new file mode 100644 index 0000000..2a76729 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b5ba523871a37543a314532e1ffe4e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs new file mode 100644 index 0000000..27bce8e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 代理类 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)] + public class RpcProxyAttribute : Attribute + { + /// + /// 构造函数 + /// + /// + public RpcProxyAttribute(string className) + { + if (string.IsNullOrEmpty(className)) + { + throw new ArgumentException($"“{nameof(className)}”不能为 null 或空。", nameof(className)); + } + + ClassName = className; + } + + /// + /// 构造函数 + /// + public RpcProxyAttribute() + { + } + + /// + /// 代理类名 + /// + public string ClassName { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs.meta new file mode 100644 index 0000000..1a1cc7e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec5c8ae5cecba224fa7d34e69f184087 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code.meta new file mode 100644 index 0000000..8e04141 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df2c578a15efc7f4fbc93598cd78d422 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs new file mode 100644 index 0000000..82abcf4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 属性单元代码。 + /// + public class ClassCellCode + { + /// + /// 属性名 + /// + public string Name { get; set; } + + /// + /// 代码本体 + /// + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs.meta new file mode 100644 index 0000000..1f5018e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCellCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9de0fd7b03d8964e946169eba58d8fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs new file mode 100644 index 0000000..822ed61 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs @@ -0,0 +1,547 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// 代码辅助类 + /// + public class ClassCodeGenerator + { + private static readonly string[] m_dicType = { "Dictionary`2", "IDictionary`2" }; + private static readonly string[] m_listType = { "List`1", "HashSet`1", "IList`1", "ISet`1", "ICollection`1", "IEnumerable`1" }; + private readonly Assembly[] m_assembly; + + /// + /// 构造函数 + /// + /// + public ClassCodeGenerator(Assembly[] assembly) + { + m_assembly = assembly; + PropertyDic = new ConcurrentDictionary(); + //GenericTypeDic = new ConcurrentDictionary(); + } + + /// + /// 程序集 + /// + public Assembly[] Assembly => m_assembly; + + ///// + ///// 泛型类型字典 + ///// + //public ConcurrentDictionary GenericTypeDic { get; private set; } + + /// + /// 属性类型字典。 + /// + public ConcurrentDictionary PropertyDic { get; private set; } + + /// + /// 获取类单元参数 + /// + /// + public ClassCellCode[] GetClassCellCodes() + { + return PropertyDic.Values.ToArray(); + } + + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(Type type) + { + if (type.FullName == null) + { + return type.Name.Replace("&", string.Empty); + } + else if (type == typeof(void)) + { + return null; + } + else if (typeof(Task).IsAssignableFrom(type)) + { + Type[] ts = type.GetGenericArguments(); + if (ts.Length == 1) + { + return ts[0].Name; + } + else + { + return type.Name; + } + } + else if (type.IsArray) + { + Type elementType = type.GetElementType(); + return GetTypeFullName(elementType) + type.Name.Replace(elementType.Name, string.Empty); + } + else if (type.IsNullableType()) + { + return GetTypeFullName(type.GetGenericArguments().Length==0? type: type.GetGenericArguments()[0]); + } + else if (type.IsValueTuple()) + { + Type[] elementTypes = type.GetGenericArguments(); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("("); + + List strings = new List(); + var tupleNames = new List(); + if (tupleElementNames != null && tupleElementNames.Count > 0) + { + tupleNames.AddRange(tupleElementNames.Skip(0).Take(elementTypes.Length)); + tupleElementNames.RemoveRange(0, elementTypes.Length); + } + for (int i = 0; i < elementTypes.Length; i++) + { + string item = GetTypeFullName(elementTypes[i]); + if (tupleNames.Count > 0) + { + strings.Add($"{item} {tupleNames[i]}"); + } + else + { + strings.Add($"{item}"); + } + } + //var strs = elementTypes.Select(e => GetTypeFullName(e)); + + + //foreach (var item in strs) + //{ + + //} + stringBuilder.Append(string.Join(",", strings)); + stringBuilder.Append(")"); + return stringBuilder.ToString(); + } + else if (type.IsByRef) + { + return GetTypeFullName(type.GetElementType()); + } + else if (type.IsPrimitive || type == typeof(string)) + { + return type.FullName; + } + else if (m_listType.Contains(type.Name)) + { + string typeInnerString = GetTypeFullName(type.GetGenericArguments()[0]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`1", string.Empty)}<{typeInnerString}>"; + return typeString; + } + else if (m_listType.Contains(type.Name) || m_dicType.Contains(type.Name)) + { + string keyString = GetTypeFullName(type.GetGenericArguments()[0]); + string valueString = GetTypeFullName(type.GetGenericArguments()[1]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"; + return typeString; + } + else if (PropertyDic.ContainsKey(type)) + { + return PropertyDic[type].Name; + } + else + { + return type.FullName; + } + } + + private List tupleElementNames; + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(ParameterInfo parameterInfo) + { + if (parameterInfo.ParameterType.FullName.Contains("System.ValueTuple")) + { + tupleElementNames = parameterInfo.GetTupleElementNames()?.ToList(); + } + else + { + tupleElementNames = default; + } + return GetTypeFullName(parameterInfo.ParameterType); + } + + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(PropertyInfo propertyInfo) + { + if (propertyInfo.PropertyType.FullName.Contains("System.ValueTuple")) + { + tupleElementNames = propertyInfo.GetTupleElementNames()?.ToList(); + } + else + { + tupleElementNames = default; + } + return GetTypeFullName(propertyInfo.PropertyType); + } + + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(FieldInfo fieldInfo) + { + if (fieldInfo.FieldType.FullName.Contains("System.ValueTuple")) + { + tupleElementNames = fieldInfo.GetTupleElementNames()?.ToList(); + } + else + { + tupleElementNames = default; + } + return GetTypeFullName(fieldInfo.FieldType); + } + + internal void CheckDeep() + { + //foreach (var strItem in GenericTypeDic) + //{ + // bool goon = true; + // string strItemNew = strItem.Value; + // while (goon) + // { + // goon = false; + // foreach (var item in GenericTypeDic.Keys) + // { + // if (strItemNew.Contains(item.FullName)) + // { + // strItemNew = strItemNew.Replace(item.FullName, item.Name); + // goon = true; + // } + // } + // } + // GenericTypeDic[strItem.Key] = strItemNew; + //} + + foreach (var strItem in PropertyDic) + { + bool goon = true; + string strItemNew = strItem.Value.Code; + while (goon) + { + goon = false; + foreach (var item in PropertyDic.Keys) + { + if (strItemNew.Contains(item.FullName)) + { + strItemNew = strItemNew.Replace(item.FullName, item.Name); + goon = true; + } + } + } + PropertyDic[strItem.Key].Code = strItemNew; + } + } + + /// + /// 添加类型字符串 + /// + /// + /// + public void AddTypeString(Type type, ref int deep) + { + if (CodeGenerator.m_ignoreTypes.Contains(type)) + { + return; + } + if (CodeGenerator.m_ignoreAssemblies.Contains(type.Assembly)) + { + return; + } + deep++; + if (deep > 50) + { + return; + } + if (type.IsByRef) + { + type = type.GetRefOutType(); + } + + if (type.IsPrimitive || type == typeof(string)) + { + return; + } + + if (type == TouchSocketCoreUtility.objType) + { + return; + } + if (type.IsInterface || type.IsAbstract) + { + return; + } + if (type.IsArray) + { + AddTypeString(type.GetElementType(), ref deep); + } + else if (type.IsGenericType) + { + Type[] types = type.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + } + else if (type.IsEnum) + { + Type baseType = Enum.GetUnderlyingType(type); + StringBuilder stringBuilder = new StringBuilder(); + if (baseType == TouchSocketCoreUtility.byteType) + { + stringBuilder.AppendLine($"public enum {type.Name}:byte"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(byte)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.shortType) + { + stringBuilder.AppendLine($"public enum {type.Name}:short"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(short)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.intType) + { + stringBuilder.AppendLine($"public enum {type.Name}:int"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(int)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.longType) + { + stringBuilder.AppendLine($"public enum {type.Name}:long"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(long)item},"); + } + } + + stringBuilder.AppendLine("}"); + if (!PropertyDic.ContainsKey(type)) + { + string className; + if (type.GetCustomAttribute() is RpcProxyAttribute attribute) + { + className = attribute.ClassName ?? type.Name; + } + else if (CodeGenerator.TryGetProxyTypeName(type, out className)) + { + } + else if (AllowGen(type.Assembly)) + { + className = type.Name; + } + else + { + return; + } + PropertyDic.TryAdd(type, new ClassCellCode() { Name = className, Code = stringBuilder.ToString() }); + } + } + else + { + string className; + if (type.GetCustomAttribute() is RpcProxyAttribute attribute) + { + className = attribute.ClassName ?? type.Name; + } + else if (CodeGenerator.TryGetProxyTypeName(type, out className)) + { + } + else if (AllowGen(type.Assembly)) + { + className = type.Name; + } + else + { + return; + } + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.AppendLine(""); + if (type.IsStruct()) + { + stringBuilder.AppendLine($"public struct {className}"); + } + else + { + stringBuilder.AppendLine($"public class {className}"); + } + + if (!type.IsStruct() && type.BaseType != typeof(object)) + { + AddTypeString(type.BaseType, ref deep); + if (type.BaseType.IsGenericType) + { + Type[] types = type.BaseType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + if (m_listType.Contains(type.BaseType.Name)) + { + string typeString = GetTypeFullName(types[0]); + stringBuilder.Append($":{type.BaseType.Name.Replace("`1", string.Empty)}<{typeString}>"); + } + else if (m_dicType.Contains(type.BaseType.Name)) + { + string keyString = GetTypeFullName(types[0]); + string valueString = GetTypeFullName(types[1]); + stringBuilder.Append($": {type.BaseType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"); + } + } + else if (type.BaseType.IsClass) + { + stringBuilder.AppendLine($": {GetTypeFullName(type.BaseType)}"); + } + } + + stringBuilder.AppendLine("{"); + foreach (PropertyInfo itemProperty in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.GetProperty | BindingFlags.SetProperty)) + { + AddTypeString(itemProperty.PropertyType, ref deep); + if (PropertyDic.ContainsKey(itemProperty.PropertyType)) + { + stringBuilder.Append($"public {itemProperty.PropertyType.Name} {itemProperty.Name}"); + } + else if (itemProperty.IsNullableType()) + { + stringBuilder.Append($"public {GetTypeFullName(itemProperty)}? {itemProperty.Name}"); + } + else if (itemProperty.PropertyType.IsGenericType) + { + Type[] types = itemProperty.PropertyType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + if (m_listType.Contains(itemProperty.PropertyType.Name)) + { + string typeString = GetTypeFullName(types[0]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`1", string.Empty)}<{typeString}> {itemProperty.Name}"); + } + else if (m_dicType.Contains(itemProperty.PropertyType.Name)) + { + string keyString = GetTypeFullName(types[0]); + string valueString = GetTypeFullName(types[1]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}> {itemProperty.Name}"); + } + } + else + { + AddTypeString(itemProperty.PropertyType, ref deep); + stringBuilder.Append($"public {GetTypeFullName(itemProperty.PropertyType)} {itemProperty.Name}"); + } + + stringBuilder.AppendLine("{get;set;}"); + } + + foreach (FieldInfo itemField in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) + { + AddTypeString(itemField.FieldType, ref deep); + if (PropertyDic.ContainsKey(itemField.FieldType)) + { + stringBuilder.Append($"public {itemField.FieldType.Name} {itemField.Name}"); + } + else if (itemField.IsNullableType()) + { + stringBuilder.Append($"public {GetTypeFullName(itemField)}? {itemField.Name}"); + } + else if (itemField.FieldType.IsGenericType) + { + Type[] types = itemField.FieldType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + if (m_listType.Contains(itemField.FieldType.Name)) + { + string typeString = GetTypeFullName(types[0]); + stringBuilder.Append($"public {itemField.FieldType.Name.Replace("`1", string.Empty)}<{typeString}> {itemField.Name}"); + } + else if (m_dicType.Contains(itemField.FieldType.Name)) + { + string keyString = GetTypeFullName(types[0]); + string valueString = GetTypeFullName(types[1]); + stringBuilder.Append($"public {itemField.FieldType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}> {itemField.Name}"); + } + } + else + { + AddTypeString(itemField.FieldType, ref deep); + stringBuilder.Append($"public {GetTypeFullName(itemField.FieldType)} {itemField.Name}"); + } + + stringBuilder.AppendLine(";"); + } + + stringBuilder.AppendLine("}"); + + if (!PropertyDic.ContainsKey(type)) + { + PropertyDic.TryAdd(type, new ClassCellCode() { Name = className, Code = stringBuilder.ToString() }); + } + } + } + + private bool AllowGen(Assembly assembly) + { + foreach (var item in m_assembly) + { + if (assembly == item) + { + return true; + } + } + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs.meta new file mode 100644 index 0000000..82dd340 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a57c3cbe02f1a424f95b72d80b4a4c09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs new file mode 100644 index 0000000..b62cb94 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs @@ -0,0 +1,552 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// 代码生成器 + /// + public static class CodeGenerator + { + internal static readonly List m_assemblies = new List(); + internal static readonly List m_ignoreAssemblies = new List(); + internal static readonly List m_ignoreTypes = new List(); + internal static readonly Dictionary m_proxyType = new Dictionary(); + private const BindingFlags m_methodFlags = BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public; + + /// + /// 添加不需要代理的程序集 + /// + /// + public static void AddIgnoreProxyAssembly(Assembly assembly) + { + m_ignoreAssemblies.Add(assembly); + } + + /// + /// 添加不需要代理的类型 + /// + /// + public static void AddIgnoreProxyType(Type type) + { + m_ignoreTypes.Add(type); + } + + /// + /// 添加需要代理的程序集 + /// + /// + public static void AddProxyAssembly(Assembly assembly) + { + m_assemblies.Add(assembly); + } + + /// + /// 添加代理类型 + /// + /// + /// + public static void AddProxyType(Type type, bool deepSearch = true) + { + if (type.IsPrimitive || type == typeof(string)) + { + return; + } + if (!m_proxyType.ContainsKey(type)) + { + RpcProxyAttribute attribute = type.GetCustomAttribute(); + m_proxyType.Add(type, attribute == null ? type.Name : attribute.ClassName); + if (deepSearch) + { + PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty); + foreach (var item in properties) + { + AddProxyType(item.PropertyType); + } + } + } + } + + /// + /// 添加代理类型 + /// + /// + /// + public static void AddProxyType(bool deepSearch = true) + { + AddProxyType(typeof(T), deepSearch); + } + + /// + /// 是否包含类型 + /// + /// + /// + public static bool ContainsType(Type type) + { + return m_proxyType.ContainsKey(type); + } + + /// + /// 转换为cs代码。 + /// + /// + /// + /// + public static string ConvertToCode(string @namespace, params ServerCellCode[] serverCodes) + { + Dictionary serverCellCodes = new Dictionary(); + Dictionary classCellCodes = new Dictionary(); + StringBuilder codeString = new StringBuilder(); + foreach (var serverCellCode in serverCodes) + { + if (serverCellCodes.ContainsKey(serverCellCode.Name)) + { + if (serverCellCode.IncludeExtension) + { + serverCellCodes[serverCellCode.Name].IncludeExtension = true; + } + + if (serverCellCode.IncludeInstance) + { + serverCellCodes[serverCellCode.Name].IncludeInstance = true; + } + + if (serverCellCode.IncludeInterface) + { + serverCellCodes[serverCellCode.Name].IncludeInterface = true; + } + + var ccm = serverCellCodes[serverCellCode.Name].Methods; + foreach (var item in serverCellCode.Methods.Keys) + { + if (!ccm.ContainsKey(item)) + { + ccm.Add(item, serverCellCode.Methods[item]); + } + } + } + else + { + serverCellCodes.Add(serverCellCode.Name, serverCellCode); + } + + foreach (var item in serverCellCode.ClassCellCodes.Keys) + { + if (!classCellCodes.ContainsKey(item)) + { + classCellCodes.Add(item, serverCellCode.ClassCellCodes[item]); + } + } + } + + string namesp = string.IsNullOrEmpty(@namespace) ? "RRQMProxy" : @namespace; + + codeString.AppendLine("using System;"); + codeString.AppendLine("using TouchSocket.Core;"); + codeString.AppendLine("using TouchSocket.Sockets;"); + codeString.AppendLine("using TouchSocket.Rpc;"); + codeString.AppendLine("using TouchSocket.Rpc.TouchRpc;"); + codeString.AppendLine("using System.Collections.Generic;"); + codeString.AppendLine("using System.Diagnostics;"); + codeString.AppendLine("using System.Text;"); + codeString.AppendLine("using System.Threading.Tasks;"); + codeString.AppendLine(string.Format("namespace {0}", namesp)); + codeString.AppendLine("{"); + + foreach (var serverCellCode in serverCellCodes.Values) + { + if (serverCellCode.IncludeInterface) + { + //接口 + codeString.AppendLine($"public interface I{serverCellCode.Name}:{typeof(IRemoteServer).FullName}");//类开始 + codeString.AppendLine("{"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.InterfaceTemple); + } + codeString.AppendLine("}"); + //接口 + } + + if (serverCellCode.IncludeInstance) + { + //类 + if (serverCellCode.IncludeInterface) + { + codeString.AppendLine($"public class {serverCellCode.Name} :I{serverCellCode.Name}");//类开始 + } + else + { + codeString.AppendLine($"public class {serverCellCode.Name}");//类开始 + } + + codeString.AppendLine("{"); + codeString.AppendLine($"public {serverCellCode.Name}(IRpcClient client)"); + codeString.AppendLine("{"); + codeString.AppendLine("this.Client=client;"); + codeString.AppendLine("}"); + codeString.AppendLine("public IRpcClient Client{get;private set; }"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.CodeTemple); + } + codeString.AppendLine("}"); + //类 + } + + if (serverCellCode.IncludeExtension) + { + //扩展类 + codeString.AppendLine($"public static class {serverCellCode.Name}Extensions");//类开始 + codeString.AppendLine("{"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.ExtensionsTemple); + } + codeString.AppendLine("}"); + //扩展类 + } + } + + foreach (var item in classCellCodes.Values) + { + codeString.AppendLine(item.Code); + } + + codeString.AppendLine("}"); + + return codeString.ToString(); + } + + /// + /// 生成代码代理 + /// + /// 服务类型 + /// 属性标签 + /// + public static ServerCellCode Generator() where TServer : IRpcServer where TAttribute : RpcAttribute + { + return Generator(typeof(TServer), typeof(TAttribute)); + } + + /// + /// 生成代码代理 + /// + /// 服务类型 + /// + /// + public static ServerCellCode Generator(Type serverType, Type attributeType) + { + ServerCellCode serverCellCode = new ServerCellCode(); + MethodInstance[] methodInstances = GetMethodInstances(serverType, serverType); + + List assemblies = new List(m_assemblies); + assemblies.Add(serverType.Assembly); + + foreach (var item in m_ignoreAssemblies) + { + assemblies.Remove(item); + } + + ClassCodeGenerator classCodeGenerator = new ClassCodeGenerator(assemblies.ToArray()); + + serverCellCode.Name = serverType.IsInterface ? + (serverType.Name.StartsWith("I") ? serverType.Name.Remove(0, 1) : serverType.Name) : serverType.Name; + List instances = new List(); + + foreach (var item in m_proxyType.Keys) + { + int deep = 0; + classCodeGenerator.AddTypeString(item, ref deep); + } + + foreach (MethodInstance methodInstance in methodInstances) + { + foreach (RpcAttribute att in methodInstance.RpcAttributes) + { + if (attributeType == att.GetType()) + { + if (methodInstance.ReturnType != null) + { + int deep = 0; + classCodeGenerator.AddTypeString(methodInstance.ReturnType, ref deep); + } + + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + for (; i < methodInstance.ParameterTypes.Length; i++) + { + int deep = 0; + classCodeGenerator.AddTypeString(methodInstance.ParameterTypes[i], ref deep); + } + + instances.Add(methodInstance); + break; + } + } + } + + classCodeGenerator.CheckDeep(); + + //foreach (var item in classCodeGenerator.GenericTypeDic.Keys.ToArray()) + //{ + // if (m_ignoreTypes.Contains(item)) + // { + // classCodeGenerator.GenericTypeDic.TryRemove(item, out _); + // } + + // if (m_ignoreAssemblies.Contains(item.Assembly)) + // { + // classCodeGenerator.GenericTypeDic.TryRemove(item, out _); + // } + //} + + foreach (var item in classCodeGenerator.PropertyDic.Keys.ToArray()) + { + if (m_ignoreTypes.Contains(item)) + { + classCodeGenerator.PropertyDic.TryRemove(item, out _); + } + + if (m_ignoreAssemblies.Contains(item.Assembly)) + { + classCodeGenerator.PropertyDic.TryRemove(item, out _); + } + } + + foreach (var item in classCodeGenerator.GetClassCellCodes()) + { + serverCellCode.ClassCellCodes.Add(item.Name, item); + } + + //ServerCodeGenerator serverCodeGenerator = new ServerCodeGenerator(classCodeGenerator); + + bool first = true; + foreach (var item in instances) + { + MethodCellCode methodCellCode = new MethodCellCode(); + RpcAttribute rpcAttribute = (RpcAttribute)item.GetAttribute(attributeType); + if (rpcAttribute == null) + { + continue; + } + rpcAttribute.SetClassCodeGenerator(classCodeGenerator); + if (first) + { + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceSync)) + { + serverCellCode.IncludeInterface = true; + } + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceSync)) + { + serverCellCode.IncludeInstance = true; + } + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync)) + { + serverCellCode.IncludeExtension = true; + } + first = false; + } + + methodCellCode.InterfaceTemple = rpcAttribute.GetInterfaceProxyCode(item); + methodCellCode.CodeTemple = rpcAttribute.GetInstanceProxyCode(item); + methodCellCode.ExtensionsTemple = rpcAttribute.GetExtensionsMethodProxyCode(item); + methodCellCode.Name = ((RpcAttribute)item.GetAttribute(attributeType)).GetMethodName(item, false); + serverCellCode.Methods.Add(methodCellCode.Name, methodCellCode); + } + + return serverCellCode; + } + + /// + /// 从类型获取函数实例 + /// + /// + /// + public static MethodInstance[] GetMethodInstances() where TServer : IRpcServer + { + return GetMethodInstances(typeof(TServer), typeof(TServer)); + } + + /// + /// 从类型获取函数实例 + /// + /// + /// + /// + public static MethodInstance[] GetMethodInstances(Type serverFromType, Type serverToType) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverFromType)) + { + throw new RpcException($"服务类型必须从{nameof(IRpcServer)}派生。"); + } + + if (!serverFromType.IsAssignableFrom(serverToType)) + { + throw new RpcException($"{serverToType}类型必须从{serverFromType}派生。"); + } + + List instances = new List(); + + var fromMethodInfos = new Dictionary(); + GetMethodInfos(serverFromType, ref fromMethodInfos); + + var toMethodInfos = new Dictionary(); + GetMethodInfos(serverToType, ref toMethodInfos); + + foreach (MethodInfo method in fromMethodInfos.Values) + { + if (method.IsGenericMethod) + { + continue; + } + IEnumerable attributes = method.GetCustomAttributes(true); + if (attributes.Count() > 0) + { + MethodInstance methodInstance = new MethodInstance(method) + { + ServerType = serverFromType, + IsEnable = true, + Parameters = method.GetParameters() + }; + if (!toMethodInfos.TryGetValue(GetMethodID(method), out var toMethod)) + { + throw new InvalidOperationException($"没有找到方法{method.Name}的实现"); + } + + List actionFilters = new List(); + foreach (var item in method.GetCustomAttributes(true)) + { + if (item is IRpcActionFilter filter) + { + actionFilters.Add(filter); + } + } + if (serverFromType!=serverToType) + { + foreach (var item in toMethod.GetCustomAttributes(true)) + { + if (item is IRpcActionFilter filter) + { + actionFilters.Add(filter); + } + } + } + + if (actionFilters.Count > 0) + { + methodInstance.Filters = actionFilters.ToArray(); + } + foreach (var item in attributes) + { + methodInstance.MethodFlags |= item.MethodFlags; + } + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (methodInstance.Parameters.Length == 0 || !typeof(ICallContext).IsAssignableFrom(methodInstance.Parameters[0].ParameterType)) + { + throw new RpcException($"函数:{method},标识包含{MethodFlags.IncludeCallContext}时,必须包含{nameof(ICallContext)}或其派生类参数,且为第一参数。"); + } + } + List names = new List(); + foreach (var parameterInfo in methodInstance.Parameters) + { + names.Add(parameterInfo.Name); + } + methodInstance.ParameterNames = names.ToArray(); + ParameterInfo[] parameters = method.GetParameters(); + List types = new List(); + foreach (var parameter in parameters) + { + types.Add(parameter.ParameterType.GetRefOutType()); + } + methodInstance.ParameterTypes = types.ToArray(); + instances.Add(methodInstance); + } + } + + return instances.ToArray(); + } + + /// + /// 生成代理代码 + /// + /// + /// + /// + /// + public static string GetProxyCodes(string @namespace, Type[] serverTypes, Type[] attributeTypes) + { + List serverCellCodeList = new List(); + foreach (var item in serverTypes) + { + foreach (var item1 in attributeTypes) + { + serverCellCodeList.Add(Generator(item, item1)); + } + } + return ConvertToCode(@namespace, serverCellCodeList.ToArray()); + } + + /// + /// 获取类型代理名称 + /// + /// + /// + /// + public static bool TryGetProxyTypeName(Type type, out string className) + { + return m_proxyType.TryGetValue(type, out className); + } + + private static string GetMethodID(MethodInfo method) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(method.Name); + foreach (var item in method.GetParameters()) + { + stringBuilder.Append(item.ParameterType.FullName); + } + + return stringBuilder.ToString(); + } + + private static void GetMethodInfos(Type type, ref Dictionary infos) + { + if (type.IsInterface) + { + foreach (var item in type.GetInterfaces()) + { + GetMethodInfos(item, ref infos); + } + } + foreach (var item in type.GetMethods(m_methodFlags)) + { + if (!infos.ContainsKey(GetMethodID(item))) + { + infos.Add(GetMethodID(item), item); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs.meta new file mode 100644 index 0000000..8ecf1d6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/CodeGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9a90055ca683ac40be1308d7b4e48e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs new file mode 100644 index 0000000..41f4889 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 生成的代码单元 + /// + + public class MethodCellCode + { + /// + /// 方法名 + /// + public string Name { get; set; } + + /// + /// 代码本体 + /// + public string CodeTemple { get; set; } + + /// + /// 接口代码。 + /// + public string InterfaceTemple { get; set; } + + /// + /// 扩展代码 + /// + public string ExtensionsTemple { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs.meta new file mode 100644 index 0000000..52afbd1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/MethodCellCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0983e6c131ff42478a70567c3db5df1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs new file mode 100644 index 0000000..5dd70d1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; + +namespace TouchSocket.Rpc +{ + /// + /// 服务单元代码 + /// + public class ServerCellCode + { + /// + /// 构造函数 + /// + public ServerCellCode() + { + methods = new Dictionary(); + classCellCodes = new Dictionary(); + } + + /// + /// 包含接口 + /// + public bool IncludeInterface { get; set; } + + /// + /// 包含实例 + /// + public bool IncludeInstance { get; set; } + + /// + /// 包含扩展 + /// + public bool IncludeExtension { get; set; } + + /// + /// 服务名 + /// + public string Name { get; set; } + + private Dictionary methods; + + /// + /// 方法集合 + /// + public Dictionary Methods + { + get => methods; + set => methods = value; + } + + private Dictionary classCellCodes; + + /// + /// 类参数集合。 + /// + public Dictionary ClassCellCodes + { + get => classCellCodes; + set => classCellCodes = value; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs.meta new file mode 100644 index 0000000..1827787 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Code/ServerCellCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70369be7a3735f5428b21475774a153d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common.meta new file mode 100644 index 0000000..6ecc217 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa38627d6c2f7d945bab39478d0b97ca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs new file mode 100644 index 0000000..b271040 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Rpc +{ + /// + /// 服务映射图 + /// + public class ActionMap : IEnumerable> + { + private readonly ConcurrentDictionary m_actionMap = new ConcurrentDictionary(); + + /// + /// 服务键集合 + /// + public IEnumerable ActionKeys => m_actionMap.Keys; + + /// + /// 添加调用 + /// + /// + /// + public void Add(string actionKey, MethodInstance methodInstance) + { + if (m_actionMap.ContainsKey(actionKey)) + { + throw new System.Exception($"调用键为{actionKey}的函数已存在。"); + } + m_actionMap.TryAdd(actionKey, methodInstance); + } + + /// + /// 获取所有服务函数实例 + /// + /// + public MethodInstance[] GetAllMethodInstances() + { + return m_actionMap.Values.ToArray(); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return m_actionMap.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_actionMap.GetEnumerator(); + } + + /// + /// 通过actionKey获取函数实例 + /// + /// + /// + public MethodInstance GetMethodInstance(string actionKey) + { + m_actionMap.TryGetValue(actionKey, out MethodInstance methodInstance); + return methodInstance; + } + + /// + /// 移除 + /// + /// + /// + public bool Remove(string actionKey, out MethodInstance methodInstance) + { + return m_actionMap.TryRemove(actionKey, out methodInstance); + } + + /// + /// 移除 + /// + /// + /// + public bool Remove(string actionKey) + { + return m_actionMap.TryRemove(actionKey, out _); + } + + /// + /// 通过actionKey获取函数实例 + /// + /// + /// + /// + public bool TryGetMethodInstance(string actionKey, out MethodInstance methodInstance) + { + return m_actionMap.TryGetValue(actionKey, out methodInstance); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs.meta new file mode 100644 index 0000000..8997709 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/ActionMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2e2b26efcb90104997aa3b4a49858a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs new file mode 100644 index 0000000..50e7a9c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 反馈类型 + /// + public enum FeedbackType : byte + { + /// + /// 仅发送 + /// + OnlySend, + + /// + /// 等待,直到发送抵达 + /// + WaitSend, + + /// + /// 等待,直到调用完成 + /// + WaitInvoke + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs.meta new file mode 100644 index 0000000..8bc982d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/FeedbackType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 294cadc9dc7b8bb44818302732d1937c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs new file mode 100644 index 0000000..72c2fc6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc +{ + /// + /// 调用结果 + /// + public struct InvokeResult + { + /// + /// 状态 + /// + public InvokeStatus Status { get; set; } + + /// + /// 信息 + /// + public string Message { get; set; } + + /// + /// 执行返回值结果 + /// + public object Result { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs.meta new file mode 100644 index 0000000..10ce2c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/InvokeResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a6c2a2d716183642a6b2b49429951fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs new file mode 100644 index 0000000..73a4183 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc函数实例 + /// + public class MethodInstance : Method + { + private RpcAttribute[] m_rpcAttributes; + + private RpcAttribute[] m_serverRpcAttributes; + + /// + /// 构造函数 + /// + /// + public MethodInstance(MethodInfo methodInfo) : base(methodInfo) + { + } + + /// + /// 描述属性 + /// + public string GetDescription() + { + return this.Info.GetCustomAttribute()?.Description; + } + + /// + /// 筛选器 + /// + public IRpcActionFilter[] Filters { get; internal set; } + + /// + /// 是否可用 + /// + public bool IsEnable { get; set; } + + /// + /// 是否为单例 + /// + public bool IsSingleton { get; internal set; } + + /// + /// 函数标识 + /// + public MethodFlags MethodFlags { get; internal set; } + + /// + /// 参数名集合 + /// + public string[] ParameterNames { get; internal set; } + + /// + /// 参数集合 + /// + public ParameterInfo[] Parameters { get; internal set; } + + /// + /// 参数类型集合,已处理out及ref,无参数时为空集合, + /// + public Type[] ParameterTypes { get; internal set; } + + /// + /// Rpc属性集合 + /// + public RpcAttribute[] RpcAttributes + { + get + { + m_rpcAttributes ??= this.Info.GetCustomAttributes(true).ToArray(); + return this.m_rpcAttributes; + } + } + + /// + /// 服务实例工厂 + /// + public IRpcServerFactory ServerFactory { get; internal set; } + + /// + /// Rpc服务属性集合 + /// + public RpcAttribute[] ServerRpcAttributes + { + get + { + m_serverRpcAttributes ??= this.ServerType.GetCustomAttributes(true).ToArray(); + return this.m_serverRpcAttributes; + } + } + + /// + /// 实例类型 + /// + public Type ServerType { get; internal set; } + + /// + /// 获取指定类型属性标签 + /// + /// + /// + public T GetAttribute() + { + object attribute = this.GetAttribute(typeof(T)); + if (attribute != null) + { + return (T)attribute; + } + return default; + } + + /// + /// 获取指定类型属性标签 + /// + /// + /// + public object GetAttribute(Type attributeType) + { + object attribute = RpcAttributes.FirstOrDefault((a) => { return attributeType.IsAssignableFrom(a.GetType()); }); + if (attribute != null) + { + return attribute; + } + + attribute = ServerRpcAttributes.FirstOrDefault((a) => { return attributeType.IsAssignableFrom(a.GetType()); }); + if (attribute != null) + { + return attribute; + } + return default; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs.meta new file mode 100644 index 0000000..d2b9d92 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/MethodInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 938ae64d6dcf56849bfb07d0a5773a0a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs new file mode 100644 index 0000000..9009995 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc范围类 + /// + public abstract class RpcServer : IRpcServer + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs.meta new file mode 100644 index 0000000..8a563af --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5693c8b20148d04f98c747012eb5e53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs new file mode 100644 index 0000000..f1ba4a3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// RpcServerFactory + /// + public class RpcServerFactory : IRpcServerFactory + { + private readonly IContainer m_container; + + /// + /// 构造函数 + /// + /// + public RpcServerFactory(IContainer container) + { + m_container = container; + } + + IRpcServer IRpcServerFactory.Create(ICallContext callContext, object[] ps) + { + return (IRpcServer)m_container.Resolve(callContext.MethodInstance.ServerType); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs.meta new file mode 100644 index 0000000..bd6788c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c75caa8f160f252489f0d228f25bd5d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs new file mode 100644 index 0000000..e29cf03 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs @@ -0,0 +1,704 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc仓库 + /// + public class RpcStore : DisposableObject, IEnumerable + { + /// + /// 命名空间 + /// + public const string Namespace = "namespace"; + + /// + /// 代理键 + /// + public const string ProxyKey = "proxy"; + + private static readonly ConcurrentDictionary m_proxyAttributeMap = new ConcurrentDictionary(); + private readonly ConcurrentDictionary m_parsers = new ConcurrentDictionary(); + private readonly ConcurrentDictionary> m_serverTypes = new ConcurrentDictionary>(); + private string m_proxyUrl = "/proxy"; + private HttpService m_service; + + static RpcStore() + { + SearchAttribute(); + } + + /// + /// 实例化一个Rpc仓库。 + /// 需要指定容器。一般和对应的服务器、客户端共用一个容器比较好。 + /// 如果,仅仅是只有一个解析器的话,可以考虑从配置中,调用 + /// + public RpcStore(IContainer container) + { + Container = container ?? throw new ArgumentNullException(nameof(container)); + Container.RegisterSingleton(this); + + if (!container.IsRegistered(typeof(IRpcServerFactory))) + { + Container.RegisterSingleton(); + } + + SearchAttribute(); + } + + /// + /// 代理属性映射。 + /// + public static ConcurrentDictionary ProxyAttributeMap => m_proxyAttributeMap; + + /// + /// 内置IOC容器 + /// + public IContainer Container { get; private set; } + + /// + /// 解析器集合。 + /// 如果想快速获得对象,请使用,一般key为对象类型名称,或自定义的。 + /// + public IRpcParser[] RpcParsers => m_parsers.Values.ToArray(); + + /// + /// 请求代理。 + /// + public Func OnRequestProxy { get; set; } + + /// + /// 代理路径。默认为“/proxy”。 + /// 必须以“/”开头 + /// + public string ProxyUrl + { + get => m_proxyUrl; + set + { + if (string.IsNullOrEmpty(value)) + { + value = "/"; + } + m_proxyUrl = value; + } + } + + /// + /// 服务类型 + /// + public Type[] ServerTypes => m_serverTypes.Keys.ToArray(); + + /// + /// 获取IRpcParser + /// + /// + /// + public IRpcParser this[string key] => m_parsers[key]; + + /// + /// 从远程获取代理 + /// + /// + /// + public static string GetProxyInfo(string url) + { + string result = Get(url); + if (string.IsNullOrEmpty(result)) + { + throw new Exception("未知错误"); + } + return result; + } + + /// + /// 添加Rpc解析器 + /// + /// 名称 + /// 解析器实例 + /// 是否应用已注册服务 + public void AddRpcParser(string key, IRpcParser parser, bool applyServer = true) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (!m_parsers.TryAdd(key, parser)) + { + throw new Exception("相同键值得解析器已经存在。"); + } + parser.SetRpcStore(this); + if (applyServer) + { + foreach (var item in m_serverTypes) + { + parser.OnRegisterServer(item.Value.ToArray()); + } + } + } + + /// + /// 获取服务类型对应的服务方法。 + /// + /// + /// + public MethodInstance[] GetServerMethodInstances(Type serverType) + { + return m_serverTypes[serverType].ToArray(); + } + + /// + /// 执行Rpc + /// + /// + /// + /// + /// + public InvokeResult Execute(IRpcServer rpcServer, object[] ps, ICallContext callContext) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + InvokeResult invokeResult = new InvokeResult(); + try + { + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].Executing(callContext,ps, ref invokeResult); + callContext.MethodInstance.Filters[i].ExecutingAsync(callContext, ps, ref invokeResult); + } + } + + if (invokeResult.Status != InvokeStatus.Ready) + { + return invokeResult; + } + + if (callContext.MethodInstance.HasReturn) + { + invokeResult.Result = callContext.MethodInstance.Invoke(rpcServer, ps); + } + else + { + callContext.MethodInstance.Invoke(rpcServer, ps); + } + invokeResult.Status = InvokeStatus.Success; + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].Executed(callContext, ps, ref invokeResult); + callContext.MethodInstance.Filters[i].ExecutedAsync(callContext, ps, ref invokeResult); + } + } + } + catch (TargetInvocationException ex) + { + invokeResult.Status = InvokeStatus.InvocationException; + if (ex.InnerException != null) + { + invokeResult.Message = "函数内部发生异常,信息:" + ex.InnerException.Message; + } + else + { + invokeResult.Message = "函数内部发生异常,信息:未知"; + } + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].ExecutException(callContext, ps, ref invokeResult, ex); + callContext.MethodInstance.Filters[i].ExecutExceptionAsync(callContext, ps, ref invokeResult, ex); + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].ExecutException(callContext, ps, ref invokeResult, ex); + callContext.MethodInstance.Filters[i].ExecutExceptionAsync(callContext, ps, ref invokeResult, ex); + } + } + } + + return invokeResult; + } + + /// + /// 获取所有已注册的函数。 + /// + public MethodInstance[] GetAllMethods() + { + List methods = new List(); + foreach (var item in m_serverTypes.Values) + { + methods.AddRange(item); + } + + return methods.ToArray(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_parsers.Values.GetEnumerator(); + } + + /// + /// 返回枚举对象 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return m_parsers.Values.GetEnumerator(); + } + + /// + /// 本地获取代理 + /// + /// + /// + /// + public string GetProxyCodes(string @namespace, Type[] attrbuteTypes) + { + var cellCodes = GetProxyInfo(attrbuteTypes == null ? ProxyAttributeMap.Values.ToArray() : attrbuteTypes); + return CodeGenerator.ConvertToCode(@namespace, cellCodes); + } + + /// + /// 本地获取代理 + /// + /// + /// + public string GetProxyCodes(string @namespace) + { + return GetProxyCodes(@namespace, null); + } + + /// + /// 从本地获取代理 + /// + /// + public ServerCellCode[] GetProxyInfo() + { + return GetProxyInfo(ProxyAttributeMap.Values.ToArray()); + } + + /// + /// 从本地获取代理 + /// + /// + /// + public ServerCellCode[] GetProxyInfo(Type[] attrbuteType) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + List codes = new List(); + + foreach (var attrbute in attrbuteType) + { + foreach (var item in m_serverTypes.Keys) + { + ServerCellCode serverCellCode = CodeGenerator.Generator(item, attrbute); + codes.Add(serverCellCode); + } + } + return codes.ToArray(); + } + + /// + /// 移除Rpc解析器 + /// + /// + /// + /// + public bool RemoveRpcParser(string parserName, out IRpcParser parser) + { + return m_parsers.TryRemove(parserName, out parser); + } + + /// + /// 移除Rpc解析器 + /// + /// + /// + public bool RemoveRpcParser(string parserName) + { + return RemoveRpcParser(parserName, out _); + } + + /// + /// 分享代理。 + /// + /// + public void ShareProxy(IPHost iPHost) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (m_service != null) + { + return; + } + m_service = new HttpService(); + m_service.Setup(new TouchSocketConfig() + .SetListenIPHosts(new IPHost[] { iPHost })) + .Start(); + + m_service.AddPlugin(new InternalPlugin(this)); + } + + /// + /// 关闭分享中心 + /// + public void StopShareProxy() + { + m_service.SafeDispose(); + } + + /// + /// 获取IRpcParser + /// + /// + /// + /// + public bool TryGetRpcParser(string key, out IRpcParser parser) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + return m_parsers.TryGetValue(key, out parser); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(IRpcServer provider) + { + return UnregisterServer(provider.GetType()); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(Type providerType) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (!typeof(IRpcServer).IsAssignableFrom(providerType)) + { + throw new RpcException("类型不相符"); + } + + if (RemoveServer(providerType, out MethodInstance[] instances)) + { + foreach (var parser in this) + { + parser.OnUnregisterServer(instances); + } + + return instances.Length; + } + return 0; + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer() where T : IRpcServer + { + return UnregisterServer(typeof(T)); + } + + internal bool TryRemove(string key, out IRpcParser parser) + { + return m_parsers.TryRemove(key, out parser); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue) + { + StopShareProxy(); + foreach (var item in this) + { + item.SafeDispose(); + } + } + + base.Dispose(disposing); + } + + private static string Get(string url) + { + string result = null; + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); + //添加参数 + HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); + Stream stream = resp.GetResponseStream(); + try + { + //获取内容 + using (StreamReader reader = new StreamReader(stream)) + { + result = reader.ReadToEnd(); + } + } + finally + { + resp.SafeDispose(); + stream.Close(); + } + return result; + } + + private static void SearchAttribute() + { + List types = new List(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + Type[] t1 = assembly.GetTypes().Where(p => typeof(RpcAttribute).IsAssignableFrom(p) && !p.IsAbstract).ToArray(); + types.AddRange(t1); + } + catch + { + } + } + + foreach (Type type in types) + { + ProxyAttributeMap.TryAdd(type.Name.Replace("Attribute", string.Empty).ToLower(), type); + } + } + + private bool RemoveServer(Type type, out MethodInstance[] methodInstances) + { + foreach (var newType in m_serverTypes.Keys) + { + if (newType.FullName == type.FullName) + { + m_serverTypes.TryRemove(newType, out var list); + methodInstances = list.ToArray(); + return true; + } + } + methodInstances = null; + return false; + } + + #region 注册 + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public void RegisterServer(Type serverFromType, IRpcServer rpcServer) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverFromType)) + { + throw new RpcException($"注册类型必须与{nameof(IRpcServer)}有继承关系"); + } + + if (!serverFromType.IsAssignableFrom(rpcServer.GetType())) + { + throw new RpcException("实例类型必须与注册类型有继承关系。"); + } + foreach (var item in m_serverTypes.Keys) + { + if (item.FullName == serverFromType.FullName) + { + throw new RpcException($"名为{serverFromType.FullName}的类型已注册。"); + } + } + + MethodInstance[] methodInstances = CodeGenerator.GetMethodInstances(serverFromType, rpcServer.GetType()); + foreach (var item in methodInstances) + { + item.IsSingleton = true; + //item.ServerFactory = new RpcServerFactory(this.Container); + item.ServerFactory = Container.Resolve() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}"); + } + m_serverTypes.TryAdd(serverFromType, new List(methodInstances)); + Container.RegisterSingleton(serverFromType, rpcServer); + + foreach (var parser in this) + { + parser.OnRegisterServer(methodInstances); + } + } + + /// + /// 注册服务 + /// + /// + /// + /// + public void RegisterServer(Type serverFromType, Type serverToType) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverFromType)) + { + throw new RpcException($"注册类型必须与{nameof(IRpcServer)}有继承关系"); + } + + if (!serverFromType.IsAssignableFrom(serverToType)) + { + throw new RpcException("实例类型必须与注册类型有继承关系。"); + } + + foreach (var item in m_serverTypes.Keys) + { + if (item.FullName == serverFromType.FullName) + { + throw new RpcException($"名为{serverFromType.FullName}的类型已注册。"); + } + } + + bool singleton; + if (typeof(ITransientRpcServer).IsAssignableFrom(serverFromType)) + { + singleton = false; + Container.RegisterTransient(serverFromType, serverToType); + } + else + { + singleton = true; + Container.RegisterSingleton(serverFromType, serverToType); + } + MethodInstance[] methodInstances = CodeGenerator.GetMethodInstances(serverFromType, serverToType); + + foreach (var item in methodInstances) + { + item.IsSingleton = singleton; + //item.ServerFactory = new RpcServerFactory(this.Container); + item.ServerFactory = Container.Resolve() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}"); + } + + m_serverTypes.TryAdd(serverFromType, new List(methodInstances)); + + foreach (var parser in this) + { + parser.OnRegisterServer(methodInstances); + } + } + + #endregion 注册 + } + + internal class InternalPlugin : HttpPluginBase + { + private readonly RpcStore m_rpcStore; + + public InternalPlugin(RpcStore rpcCerter) + { + m_rpcStore = rpcCerter; + } + + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (e.Context.Request.UrlEquals(m_rpcStore.ProxyUrl)) + { + bool? b = m_rpcStore.OnRequestProxy?.Invoke(e.Context.Request); + if (b == false) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + e.Context.Response + .FromText("拒绝响应内容") + .SetStatus("403", "Forbidden") + .Build(byteBlock); + client.DefaultSend(byteBlock); + } + return; + } + string value = e.Context.Request.Query[RpcStore.ProxyKey]; + List types = new List(); + + if (value.Equals("all", StringComparison.CurrentCultureIgnoreCase)) + { + types = RpcStore.ProxyAttributeMap.Values.ToList(); + } + else + { + string[] vs = value.Split(','); + foreach (var item in vs) + { + if (RpcStore.ProxyAttributeMap.TryGetValue(item, out Type type)) + { + types.Add(type); + } + } + } + + string names = e.Context.Request.Query[RpcStore.Namespace]; + + names = string.IsNullOrEmpty(names) ? "RRQMProxy" : names; + + string code = CodeGenerator.ConvertToCode(names, m_rpcStore.GetProxyInfo(types.ToArray())); + + using (ByteBlock byteBlock = new ByteBlock()) + { + e.Context.Response + .SetStatus() + .SetContent(code) + .SetContentTypeFromFileName($"{names}.cs") + .Build(byteBlock); + client.DefaultSend(byteBlock); + } + } + base.OnGet(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs.meta new file mode 100644 index 0000000..0e7cc11 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/RpcStore.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e024ac9f3c2edd4782126f36779bae2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs new file mode 100644 index 0000000..a302872 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// TransientRpcServer + /// + public abstract class TransientRpcServer : RpcServer, ITransientRpcServer where TCallContext : ICallContext + { + ICallContext ITransientRpcServer.CallContext { get; set; } + + /// + /// 调用上下文。 + /// + protected TCallContext CallContext => (((ITransientRpcServer)this).CallContext is TCallContext Transient) ? Transient : default; + } + + /// + /// TransientRpcServer + /// + public abstract class TransientRpcServer : RpcServer, ITransientRpcServer + { + ICallContext ITransientRpcServer.CallContext { get; set; } + + /// + /// 调用上下文。 + /// + protected ICallContext CallContext => ((ITransientRpcServer)this).CallContext; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs.meta new file mode 100644 index 0000000..3e70acb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca740835db72bb74da4afa00963f3cd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum.meta new file mode 100644 index 0000000..bd02745 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0906eca951ebde468414d4282fd92cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs new file mode 100644 index 0000000..deb3de8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 代码生成标识 + /// + [Flags] + public enum CodeGeneratorFlag + { + /// + /// 生成同步代码(源代码生成无效) + /// + [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] + Sync = 1, + + /// + /// 生成异步代码(源代码生成无效) + /// + [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] + Async = 2, + + /// + /// 生成扩展同步代码 + /// + ExtensionSync = 4, + + /// + /// 生成扩展异步代码 + /// + ExtensionAsync = 8, + + /// + /// 包含接口(源代码生成无效) + /// + [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] + IncludeInterface = 16, + + /// + /// 包含实例(源代码生成无效) + /// + [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] + IncludeInstance = 32, + + /// + /// 包含扩展(源代码生成无效) + /// + [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] + IncludeExtension = 64, + + /// + /// 生成实例类同步代码(源代码生成无效) + /// + InstanceSync = 128, + + /// + /// 生成实例类异步代码(源代码生成无效) + /// + InstanceAsync = 256, + + /// + /// 生成接口同步代码 + /// + InterfaceSync = 512, + + /// + /// 生成接口异步代码 + /// + InterfaceAsync = 1024, + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs.meta new file mode 100644 index 0000000..fa470fd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 523438adc8481a94bb512d1fa5dee62b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs new file mode 100644 index 0000000..c4513d2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 调用状态 + /// + public enum InvokeStatus : byte + { + /// + /// 就绪 + /// + Ready, + + /// + /// 未找到服务 + /// + UnFound, + + /// + /// 不可用 + /// + UnEnable, + + /// + /// 成功调用 + /// + Success, + + /// + /// 调用内部异常 + /// + InvocationException, + + /// + /// 其他异常 + /// + Exception + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs.meta new file mode 100644 index 0000000..ea83ce4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e14da205d4f8e54408ff9038dcc40f36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs new file mode 100644 index 0000000..ffbeac1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 函数标识 + /// + [Flags] + public enum MethodFlags + { + /// + /// 空 + /// + None = 1, + + /// + /// 包含调用上下文 + /// + IncludeCallContext = 2 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs.meta new file mode 100644 index 0000000..d50b485 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Enum/MethodFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c0edd42cdd907d4e9acccef0ea127e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions.meta new file mode 100644 index 0000000..01a550a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 529e4aef9de650c4597218c868c0b3c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs new file mode 100644 index 0000000..6b6775a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc异常 + /// + [Serializable] + public class RpcException : Exception + { + /// + ///构造函数 + /// + public RpcException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// Rpc调用异常 + /// + [Serializable] + public class RpcInvokeException : Exception + { + /// + ///构造函数 + /// + public RpcInvokeException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcInvokeException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcInvokeException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcInvokeException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs.meta new file mode 100644 index 0000000..10cd056 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f266674de22b0aa46833426b9cbda227 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions.meta new file mode 100644 index 0000000..ef5518a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da4be79ec91b2f04a9442f99772c2595 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs new file mode 100644 index 0000000..71ed437 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Rpc; + +namespace TouchSocket.Core +{ + /// + /// RpcExtensions + /// + public static class RpcConfigExtensions + { + /// + /// 指定RpcStore的创建。 + /// + public static readonly DependencyProperty RpcStoreProperty = + DependencyProperty.Register("RpcStore", typeof(RpcConfigExtensions), null); + + /// + /// 配置RpcStore的创建。 + /// + /// + /// 当RpcStore完成配置时回调 + public static TouchSocketConfig ConfigureRpcStore(this TouchSocketConfig config, Action action) + { + var value = config.GetValue(RpcStoreProperty); + if (value == default) + { + value = new RpcStore(config.Container); + config.SetValue(RpcStoreProperty, value); + } + action?.Invoke(value); + return config; + } + + /// + /// 配置RpcStore的创建。 + /// + /// + /// 当RpcStore完成配置时回调 + /// 可以使用现有的值,如果赋值为null,则会重新创建。 + public static TouchSocketConfig ConfigureRpcStore(this TouchSocketConfig config, Action action, RpcStore value = default) + { + if (value == default) + { + value = new RpcStore(config.Container); + } + action?.Invoke(value); + config.SetValue(RpcStoreProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs.meta new file mode 100644 index 0000000..5688334 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e673c8dc67a74848bb86932473f7183 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs new file mode 100644 index 0000000..6adde29 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs @@ -0,0 +1,198 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// RpcParserExtensions + /// + public static class RpcParserExtensions + { + /// + /// 获取本地代理 + /// + /// + /// + /// + /// + public static string GetProxyCodes(this IRpcParser rpcParser, string @namespace, Type[] attrbuteTypes) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.GetProxyCodes(@namespace, attrbuteTypes); + } + + /// + /// 获取本地代理 + /// + /// + /// + /// + public static string GetProxyCodes(this IRpcParser rpcParser, string @namespace) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.GetProxyCodes(@namespace, null); + } + + /// + /// 注册所有服务 + /// + /// 返回搜索到的服务数 + public static int RegisterAllServer(this IRpcParser rpcParser) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.RegisterAllServer(); + } + + /// + /// 注册所有服务 + /// + /// 返回注册实例 + public static void RegisterServer(this IRpcParser rpcParser) where TFrom : class, IRpcServer where TTo : TFrom + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(); + } + + /// + /// 注册服务 + /// + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type providerInterfaceType, Type providerType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(providerInterfaceType, providerType); + } + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, TFrom serverProvider) where TFrom : class, IRpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(serverProvider); + } + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type providerInterfaceType, IRpcServer serverProvider) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(providerInterfaceType, serverProvider); + } + + /// + /// 注册服务 + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser) where T : IRpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type fromType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(fromType); + } + + /// + /// 移除注册服务 + /// + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser, IRpcServer provider) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(provider); + } + + /// + /// 移除注册服务 + /// + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser, Type providerType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(providerType); + } + + /// + /// 移除注册服务 + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser) where T : RpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs.meta new file mode 100644 index 0000000..4fde98c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a984b9ff446edb24692053abbb255ae5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs new file mode 100644 index 0000000..b4fc6b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Rpc +{ + /// + /// RpcStoreExtensions + /// + public static class RpcStoreExtensions + { + /// + /// 注册所有服务 + /// + /// 返回搜索到的服务数 + public static int RegisterAllServer(this RpcStore rpcStore) + { + List types = new List(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + Type[] t1 = assembly.GetTypes().Where(p => typeof(IRpcServer).IsAssignableFrom(p) && !p.IsAbstract && p.IsClass).ToArray(); + types.AddRange(t1); + } + catch + { + } + } + + foreach (Type type in types) + { + rpcStore.RegisterServer(type); + } + return types.Count; + } + + /// + /// 注册服务 + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore) where T : IRpcServer + { + rpcStore.RegisterServer(typeof(T)); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore, Type providerType) + { + rpcStore.RegisterServer(providerType, providerType); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore) where TFrom : class, IRpcServer where TTo : TFrom + { + rpcStore.RegisterServer(typeof(TFrom), typeof(TTo)); + } + + /// + /// 注册为单例服务 + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore, TFrom rpcServer) where TFrom : class, IRpcServer + { + rpcStore.RegisterServer(typeof(TFrom), rpcServer); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs.meta new file mode 100644 index 0000000..0c1844c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c0ed3dff61adc04ea343a0fa8b3cddb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface.meta new file mode 100644 index 0000000..da2738b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cd2191048c51ee49bb003602d1c8194 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs new file mode 100644 index 0000000..117b6a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc +{ + /// + /// 调用上下文 + /// + public interface ICallContext + { + /// + /// 调用此服务的主体。 + /// + /// + /// 当该服务在及派生中调用时,该值一般为对象。 + /// 当该服务在及派生中调用时,该值一般为对象。 + /// 当该服务在及派生中调用时,该值一般为对象。 + /// + /// + /// + object Caller { get; } + + /// + /// 本次调用的 + /// + MethodInstance MethodInstance { get; } + + /// + /// 可取消的调用令箭 + /// + CancellationTokenSource TokenSource { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs.meta new file mode 100644 index 0000000..039c9cb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ICallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b43b347da246c9d43989de09f6e95658 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs new file mode 100644 index 0000000..210b989 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; + +namespace TouchSocket.Rpc +{ + /// + /// 调用配置接口 + /// + public interface IInvokeOption + { + /// + /// 可以取消的调用令箭 + /// + public CancellationToken Token { get; set; } + + /// + /// 调用反馈 + /// + public FeedbackType FeedbackType { get; set; } + + /// + /// 调用超时 + /// + public int Timeout { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs.meta new file mode 100644 index 0000000..2d82f75 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ca057f924f11cd4c9a412649e9ebdaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs new file mode 100644 index 0000000..b1c9c6e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 远程服务接口 + /// + public interface IRemoteServer + { + /// + /// 客户端 + /// + IRpcClient Client { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs.meta new file mode 100644 index 0000000..e1e1569 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6da825a8b83e6b5419c3baaf38754113 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs new file mode 100644 index 0000000..4cc60cc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading.Tasks; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc接口 + /// + public interface IRpcClient : IDisposable + { + /// + /// 检验能否执行Rpc调用 + /// + Func TryCanInvoke { get; set; } + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 服务器返回结果 + T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// 对应类型集合 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 返回值 + T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// Rpc调用 + /// + /// 调用键 + /// 参数 + /// + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 服务器返回结果 + Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs.meta new file mode 100644 index 0000000..103566a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28157ba1cd9e8b8438ad8c702321a39e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs new file mode 100644 index 0000000..215cefb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc解析器 + /// + public interface IRpcParser : IDisposable + { + /// + /// RPC仓库。 + /// + public RpcStore RpcStore { get; } + + /// + /// 设置此解析器的服务器实例 + /// + void SetRpcStore(RpcStore rpcStore); + + /// + /// 注册服务 + /// + /// + void OnRegisterServer(MethodInstance[] methodInstances); + + /// + /// 取消注册服务 + /// + /// + void OnUnregisterServer(MethodInstance[] methodInstances); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs.meta new file mode 100644 index 0000000..6277242 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 124c2e053a84b7341af3228f5f875437 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs new file mode 100644 index 0000000..8b0ed87 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc服务接口 + /// + public interface IRpcServer + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs.meta new file mode 100644 index 0000000..81c6540 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7a6aa8623b2ede49b58288131e47c90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs new file mode 100644 index 0000000..0eb92a9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// IRpcServerFactory + /// + public interface IRpcServerFactory + { + /// + /// 创建rpc实例 + /// + /// + /// + /// + public IRpcServer Create(ICallContext callContext, object[] ps); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs.meta new file mode 100644 index 0000000..565e3c2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7d27e2f05bced64c953a2c6ce7f171e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs new file mode 100644 index 0000000..cce1021 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc服务接口 + /// + public interface ITransientRpcServer : IRpcServer + { + /// + /// 调用上下文 + /// + ICallContext CallContext { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs.meta new file mode 100644 index 0000000..863ecbe --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7783e6218d77bfe4e923db01a796522e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc.meta new file mode 100644 index 0000000..bb642fc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39ce8b0f5c34d634a8452a3ff0514003 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute.meta new file mode 100644 index 0000000..902db70 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81a7e99d8622f2d4881dd9285c5a2522 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs new file mode 100644 index 0000000..c5cc801 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// 适用于JsonRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class JsonRpcAttribute : RpcAttribute + { + /// + /// 适用于JsonRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public JsonRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于JsonRpc的标记. + /// + /// + public JsonRpcAttribute(string invokenKey) + { + InvokeKey = invokenKey; + } + + /// + /// + /// + /// + public override Type[] GetGenericConstraintTypes() + { + return new Type[] { typeof(IJsonRpcClient) }; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs.meta new file mode 100644 index 0000000..3b4b1dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 385e60cc68a62a643ac3107dbc803bea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common.meta new file mode 100644 index 0000000..601ff2b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31d0f8601564f2843ae64fbc67dd105e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs new file mode 100644 index 0000000..13caeb2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc响应器 + /// + public class JsonResponseContext + { + /// + /// jsonrpc + /// + public string jsonrpc { get; set; } + + /// + /// result + /// + public object result { get; set; } + + /// + /// error + /// + public error error { get; set; } + + /// + /// id + /// + public string id { get; set; } + } + + /// + /// 错误 + /// +#pragma warning disable IDE1006 // 命名样式 + + public class error +#pragma warning restore IDE1006 // 命名样式 + { + /// + /// code + /// + public int code { get; set; } + + /// + /// message + /// + public string message { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs.meta new file mode 100644 index 0000000..fb34c75 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ba9f0d648f3d8a4e827e81a778c72fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs new file mode 100644 index 0000000..af69df5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc调用上下文 + /// + internal class JsonRpcCallContext : IJsonRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// Json字符串 + /// + public string JsonString { get; internal set; } + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// JsonRpc上下文 + /// + public JsonRpcContext JsonRpcContext { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// + /// + public HttpContext HttpContext { get; internal set; } + + /// + /// + /// + public JRPT JRPT { get; internal set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs.meta new file mode 100644 index 0000000..37b4047 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37ac1bcddeeb8a347ba8d2186dc21373 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs new file mode 100644 index 0000000..d8dcaf7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcPackage + /// + public class JsonRpcContext : JsonRpcRequest + { + /// + /// parameters + /// + public object[] parameters; + + /// + /// needResponse + /// + public bool needResponse; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs.meta new file mode 100644 index 0000000..e3ba9e7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b93c142b79230c44a97992904b0fb43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs new file mode 100644 index 0000000..b67ae22 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcRequest + /// + public class JsonRpcRequest + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// method + /// + public string method; + + /// + /// @params + /// + public object @params; + + /// + /// id + /// + public string id; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs.meta new file mode 100644 index 0000000..48bee63 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 961d392fcb616a24eb88b21dc009383b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs new file mode 100644 index 0000000..06515d1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcSuccessResponse + /// + public class JsonRpcSuccessResponse + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// result + /// + public object result; + + /// + /// id + /// + public string id; + } + + /// + /// JsonRpcErrorResponse + /// + public class JsonRpcErrorResponse + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// error + /// + public error error; + + /// + /// id + /// + public string id; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs.meta new file mode 100644 index 0000000..2614535 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aaef332935afc4d448266666496dff47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs new file mode 100644 index 0000000..315554b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.JsonRpc +{ + internal class JsonRpcWaitResult : WaitResult + { + internal object Return; + + internal error error; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs.meta new file mode 100644 index 0000000..adc5f54 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9035a0bbaf5fc0c4dbab97eaa389d0c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components.meta new file mode 100644 index 0000000..c874daf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8af4b1ebf2001474b95d81c3eb7b92f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs new file mode 100644 index 0000000..f4c8359 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs @@ -0,0 +1,874 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Http.WebSockets; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc客户端 + /// + public class JsonRpcClient : DisposableObject, ITcpClient, IJsonRpcClient + { + private readonly WaitHandlePool m_waitHandle; + private JRPT m_jrpt; + + /// + /// 构造函数 + /// + public JsonRpcClient() + { + m_waitHandle = new WaitHandlePool(); + } + + /// + /// + /// + public int BufferLength => Client.BufferLength; + + /// + /// + /// + public bool CanSend => Client.CanSend; + + /// + /// + /// + public bool CanSetDataHandlingAdapter => Client.CanSetDataHandlingAdapter; + + /// + /// 内部客户端 + /// + public ITcpClient Client { get; private set; } + + /// + /// + /// + public TouchSocketConfig Config => Client.Config; + + /// + /// + /// + public MessageEventHandler Connected { get => Client.Connected; set => Client.Connected = value; } + + /// + /// + /// + public ConnectingEventHandler Connecting { get => Client.Connecting; set => Client.Connecting = value; } + + /// + /// + /// + public IContainer Container => ((IClient)Client).Container; + + /// + /// + /// + public DataHandlingAdapter DataHandlingAdapter => Client.DataHandlingAdapter; + + /// + /// + /// + public DisconnectEventHandler Disconnected { get => Client.Disconnected; set => Client.Disconnected = value; } + + /// + public DisconnectEventHandler Disconnecting { get => Client.Disconnecting; set => Client.Disconnecting = value; } + + /// + /// + /// + public string IP => Client.IP; + + /// + public bool IsClient => Client.IsClient; + + /// + /// 协议类型 + /// + public JRPT JRPT => m_jrpt; + + /// + /// + /// + public DateTime LastReceivedTime => Client.LastReceivedTime; + + /// + /// + /// + public DateTime LastSendTime => Client.LastSendTime; + + /// + /// + /// + public ILog Logger => Client.Logger; + + /// + /// + /// + public Socket MainSocket => Client.MainSocket; + + /// + /// + /// + public Func OnHandleRawBuffer { get => Client.OnHandleRawBuffer; set => Client.OnHandleRawBuffer = value; } + + /// + /// + /// + public Func OnHandleReceivedData { get => Client.OnHandleReceivedData; set => Client.OnHandleReceivedData = value; } + + /// + /// + /// + public bool Online => Client.Online; + + /// + /// + /// + public IPluginsManager PluginsManager => Client.PluginsManager; + + /// + /// + /// + public int Port => Client.Port; + + /// + /// + /// + public Protocol Protocol { get => Client.Protocol; set => Client.Protocol = value; } + + /// + /// + /// + public ReceiveType ReceiveType => Client.ReceiveType; + + /// + /// + /// + public IPHost RemoteIPHost => Client.RemoteIPHost; + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// + /// + public bool UsePlugin => Client.UsePlugin; + + /// + /// + /// + public bool UseSsl => Client.UseSsl; + + /// + /// + /// + public void Close() + { + Client.Close(); + } + + /// + /// + /// + public void Close(string msg) + { + Client.Close(msg); + } + + /// + /// + /// + public ITcpClient Connect(int timeout = 5000) + { + Client.OnHandleReceivedData = HandleReceivedData; + Client.Connect(timeout); + return this; + } + + /// + /// + /// + public Task ConnectAsync(int timeout = 5000) + { + return EasyTask.Run(() => + { + return Connect(timeout); + }); + } + + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + Client.DefaultSend(buffer, offset, length); + } + + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return Client.DefaultSendAsync(buffer, offset, length); + } + + /// + /// + /// + public Stream GetStream() + { + return Client.GetStream(); + } + + /// + /// + /// + public TValue GetValue(IDependencyProperty dp) + { + return Client.GetValue(dp); + } + + /// + /// + /// + public void Send(byte[] buffer, int offset, int length) + { + Client.Send(buffer, offset, length); + } + + /// + /// + /// + public void Send(IRequestInfo requestInfo) + { + Client.Send(requestInfo); + } + + /// + /// + /// + public void Send(IList> transferBytes) + { + Client.Send(transferBytes); + } + + /// + /// + /// + public Task SendAsync(byte[] buffer, int offset, int length) + { + return Client.SendAsync(buffer, offset, length); + } + + /// + /// + /// + public Task SendAsync(IRequestInfo requestInfo) + { + return Client.SendAsync(requestInfo); + } + + /// + /// + /// + public Task SendAsync(IList> transferBytes) + { + return Client.SendAsync(transferBytes); + } + + /// + /// + /// + public void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + Client.SetDataHandlingAdapter(adapter); + } + + /// + /// + /// + public ITcpClient Setup(TouchSocketConfig config) + { + m_jrpt = config.GetValue(JsonRpcConfigExtensions.JRPTProperty); + switch (m_jrpt) + { + case JRPT.Http: + Client ??= new HttpClient(); + break; + + case JRPT.Websocket: + Client ??= new WebSocketClient(); + break; + + case JRPT.Tcp: + default: + Client ??= new Sockets.TcpClient(); + break; + } + return Client.Setup(config); + } + + /// + /// + /// + public ITcpClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return Setup(config); + } + + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value) + { + return Client.SetValue(dp, value); + } + + /// + /// 处理数据 + /// + /// + /// + private bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + string jsonString = null; + switch (m_jrpt) + { + case JRPT.Http: + { + HttpResponse httpResponse = (HttpResponse)requestInfo; + jsonString = httpResponse.GetBody(); + break; + } + case JRPT.Websocket: + { + if (requestInfo is WSDataFrame dataFrame && dataFrame.Opcode == WSDataType.Text) + { + jsonString = dataFrame.ToText(); + } + break; + } + case JRPT.Tcp: + default: + { + if (byteBlock == null) + { + return true; + } + else + { + jsonString = byteBlock.ToString(); + } + break; + } + } + + if (string.IsNullOrEmpty(jsonString)) + { + return true; + } + + try + { + if (jsonString.Contains("error") || jsonString.Contains("result")) + { + JsonResponseContext responseContext = jsonString.FromJson(); + if (responseContext != null && !responseContext.id.IsNullOrEmpty()) + { + JsonRpcWaitResult waitContext = new JsonRpcWaitResult + { + Status = 1, + Sign = long.Parse(responseContext.id), + error = responseContext.error, + Return = responseContext.result + }; + m_waitHandle.SetRun(waitContext); + } + } + } + catch + { + } + return true; + } + + #region RPC调用 + + /// + /// + /// + /// + /// + public bool HasValue(IDependencyProperty dp) + { + return Client.HasValue(dp); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + waitData.Wait(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + + if (resultContext.Return == null) + { + return default; + } + if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) + { + return (T)resultContext.Return.ToString().ParseToType(typeof(T)); + } + + return resultContext.Return.ToJson().FromJson(); + } + default: + return default; + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + } + break; + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + waitData.Wait(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + break; + } + default: + return; + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + public async Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + } + break; + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + await waitData.WaitAsync(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + break; + } + default: + return; + } + } + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public async Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + await waitData.WaitAsync(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + + if (resultContext.Return == null) + { + return default; + } + if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) + { + return (T)resultContext.Return.ToString().ParseToType(typeof(T)); + } + + return resultContext.Return.ToJson().FromJson(); + } + default: + return default; + } + } + } + + /// + /// + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp) + { + return Client.RemoveValue(dp); + } + + #endregion RPC调用 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs.meta new file mode 100644 index 0000000..ee82b08 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70e18c78aefa9b046ae7804333a5ce95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config.meta new file mode 100644 index 0000000..47e7c78 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ff7e76119021504da6ee3c4a84e17d1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs new file mode 100644 index 0000000..e3976f0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.JsonRpc; + +namespace TouchSocket.Sockets +{ + /// + /// JsonRpcConfigExtensions + /// + public static class JsonRpcConfigExtensions + { + /// + /// 构建JsonRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithJsonRpcClient(this TouchSocketConfig config) where TClient : IJsonRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建JsonRpc类客户端,并连接 + /// + /// + /// + public static JsonRpcClient BuildWithJsonRpcClient(this TouchSocketConfig config) + { + return BuildWithJsonRpcClient(config); + } + + /// + /// TcpJsonRpc + /// + public static Protocol TcpJsonRpc { get; private set; } = new Protocol("TcpJsonRpc"); + + /// + /// 转化Protocol协议标识 + /// + /// + public static void SwitchProtocolToTcpJsonRpc(this ITcpClientBase client) + { + client.Protocol = TcpJsonRpc; + } + + /// + /// 设置JsonRpc的协议。 + /// + public static readonly DependencyProperty JRPTProperty = + DependencyProperty.Register("JRPT", typeof(JsonRpcConfigExtensions), JRPT.Tcp); + + /// + /// 设置JsonRpc的协议。默认为 + /// + /// + /// + /// + public static TouchSocketConfig SetJRPT(this TouchSocketConfig config, JRPT value) + { + config.SetValue(JRPTProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs.meta new file mode 100644 index 0000000..320d22c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be6c0b16cf084f146a17883becac7706 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum.meta new file mode 100644 index 0000000..29a34d4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 850a4dcd72b228042ba7310a46b14685 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs new file mode 100644 index 0000000..103e658 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc协议类型 + /// + public enum JRPT : byte + { + /// + /// 普通TCP协议 + /// + Tcp, + + /// + /// Http协议 + /// + Http, + + /// + /// Websocket协议 + /// + Websocket + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs.meta new file mode 100644 index 0000000..9049bb3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be0ba9671ef45db4fb7a96c12394897a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions.meta new file mode 100644 index 0000000..da1b7d8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1cd2ac0028575be44aa099ccdc325802 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs new file mode 100644 index 0000000..f8b0465 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.JsonRpc; + +namespace TouchSocket.Core +{ + /// + /// JsonRpcPluginsManagerExtension + /// + public static class JsonRpcPluginsManagerExtension + { + /// + /// 使用JsonRpc的插件。仅服务器可用。 + /// + /// + /// + public static JsonRpcParserPlugin UseJsonRpc(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..2681d3b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59215a9a6dbca7544af7369fa0b54a41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface.meta new file mode 100644 index 0000000..8abb575 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0400d21714a27404fb6ae1533ed0ac2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs new file mode 100644 index 0000000..999c48d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// IJsonRpcCallContext + /// + public interface IJsonRpcCallContext : IHttpCallContext + { + /// + /// Json字符串 + /// + public string JsonString { get; } + + /// + /// JsonRpc数据包 + /// + public JsonRpcContext JsonRpcContext { get; } + + /// + /// 表明当前的调用协议。 + /// + JRPT JRPT { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs.meta new file mode 100644 index 0000000..3cfd1af --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2cc7efd6399ebb34da44d2c8be0fe480 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs new file mode 100644 index 0000000..09f108e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// IJsonRpcClient + /// + public interface IJsonRpcClient : ITcpClient, IRpcClient + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs.meta new file mode 100644 index 0000000..1df4f97 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7cc040027279234b82ca184a4fe7ff6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins.meta new file mode 100644 index 0000000..5775700 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86c181f51d3934f46814ae46f7b71b27 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs new file mode 100644 index 0000000..a8831a9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs @@ -0,0 +1,430 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Http.WebSockets; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcParser解析器插件 + /// + public class JsonRpcParserPlugin : WebSocketPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private string m_jsonRpcUrl = "/jsonrpc"; + private RpcStore m_rpcStore; + + /// + /// 构造函数 + /// + public JsonRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// JsonRpc的调用键。 + /// + public ActionMap ActionMap => m_actionMap; + + /// + /// 自动转换协议 + /// + public bool AutoSwitch { get; set; } = true; + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + public string JsonRpcUrl + { + get => m_jsonRpcUrl; + set => m_jsonRpcUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + /// + /// + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 不需要自动转化协议。 + /// 仅当服务器是TCP时生效。此时如果携带协议为TcpJsonRpc时才会解释为jsonRpc。 + /// + /// + public JsonRpcParserPlugin NoSwitchProtocol() + { + AutoSwitch = false; + return this; + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is JsonRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is JsonRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + /// + /// + public JsonRpcParserPlugin SetJsonRpcUrl(string jsonRpcUrl) + { + JsonRpcUrl = jsonRpcUrl; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnConnecting(ITcpClientBase client, OperationEventArgs e) + { + if (AutoSwitch && client.Protocol == Protocol.TCP) + { + client.SwitchProtocolToTcpJsonRpc(); + } + base.OnConnecting(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Text) + { + string jsonRpcStr = e.DataFrame.ToText(); + if (jsonRpcStr.Contains("jsonrpc")) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Websocket, + JsonString = jsonRpcStr + }); + } + } + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_jsonRpcUrl == "/" || e.Context.Request.UrlEquals(m_jsonRpcUrl)) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Http, + JsonString = e.Context.Request.GetBody(), + HttpContext = e.Context + }); + } + base.OnPost(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (client.Protocol == JsonRpcConfigExtensions.TcpJsonRpc) + { + string jsonRpcStr = e.ByteBlock.ToString(); + if (jsonRpcStr.Contains("jsonrpc")) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Tcp, + JsonString = e.ByteBlock.ToString() + }); + } + } + base.OnReceivedData(client, e); + } + + private static void Response(JsonRpcCallContext callContext, object result, error error) + { + try + { + using (ByteBlock responseByteBlock = new ByteBlock()) + { + object jobject = null; + if (error == null) + { + jobject = new JsonRpcSuccessResponse + { + result = result, + id = callContext.JsonRpcContext.id + }; + } + else + { + jobject = new JsonRpcErrorResponse + { + error = error, + id = callContext.JsonRpcContext.id + }; + } + ITcpClientBase client = (ITcpClientBase)callContext.Caller; + if (callContext.JRPT == JRPT.Http) + { + HttpResponse httpResponse = callContext.HttpContext.Response; + httpResponse.FromJson(jobject.ToJson()); + httpResponse.Answer(); + } + else if (callContext.JRPT == JRPT.Websocket) + { + ((HttpSocketClient)client).SendWithWS(jobject.ToJson()); + } + else + { + responseByteBlock.Write(jobject.ToJson().ToUTF8Bytes()); + client.Send(responseByteBlock); + } + } + } + catch + { + } + } + + private void BuildRequestContext(ref JsonRpcCallContext callContext) + { + JsonRpcContext jsonRpcContext = SerializeConvert.JsonDeserializeFromString(callContext.JsonString); + callContext.JsonRpcContext = jsonRpcContext; + if (jsonRpcContext.id != null) + { + jsonRpcContext.needResponse = true; + } + + if (m_actionMap.TryGetMethodInstance(jsonRpcContext.method, out MethodInstance methodInstance)) + { + callContext.MethodInstance = methodInstance; + if (jsonRpcContext.@params == null) + { + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (methodInstance.ParameterNames.Length > 1) + { + throw new RpcException("调用参数计数不匹配"); + } + else + { + jsonRpcContext.parameters = new object[] { callContext }; + } + } + else + { + if (methodInstance.ParameterNames.Length != 0) + { + throw new RpcException("调用参数计数不匹配"); + } + } + } + if (jsonRpcContext.@params is Dictionary obj) + { + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + //内联 + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + jsonRpcContext.parameters[0] = callContext; + i = 1; + } + for (; i < methodInstance.ParameterNames.Length; i++) + { + if (obj.TryGetValue(methodInstance.ParameterNames[i], out object jToken)) + { + Type type = methodInstance.ParameterTypes[i]; + jsonRpcContext.parameters[i] = jToken.ToJson().FromJson(type); + } + else if (methodInstance.Parameters[i].HasDefaultValue) + { + jsonRpcContext.parameters[i] = methodInstance.Parameters[i].DefaultValue; + } + else + { + throw new RpcException("调用参数计数不匹配"); + } + } + } + else + { + IList array = (IList)jsonRpcContext.@params; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (array.Count != methodInstance.ParameterNames.Length - 1) + { + throw new RpcException("调用参数计数不匹配"); + } + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + + jsonRpcContext.parameters[0] = callContext; + for (int i = 0; i < array.Count; i++) + { + jsonRpcContext.parameters[i + 1] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i + 1]); + } + } + else + { + if (array.Count != methodInstance.ParameterNames.Length) + { + throw new RpcException("调用参数计数不匹配"); + } + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + + for (int i = 0; i < array.Count; i++) + { + jsonRpcContext.parameters[i] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i]); + } + } + } + } + } + + private void InvokeWaitCallback(object context) + { + if (context is null) + { + return; + } + JsonRpcCallContext callContext = (JsonRpcCallContext)context; + InvokeResult invokeResult = new InvokeResult(); + + try + { + BuildRequestContext(ref callContext); + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + + if (callContext.MethodInstance != null) + { + if (!callContext.MethodInstance.IsEnable) + { + invokeResult.Status = InvokeStatus.UnEnable; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = callContext.MethodInstance.ServerFactory.Create(callContext, callContext.JsonRpcContext.parameters); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + + invokeResult = m_rpcStore.Execute(rpcServer, callContext.JsonRpcContext.parameters, callContext); + } + + if (!callContext.JsonRpcContext.needResponse) + { + return; + } + error error = null; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + break; + } + case InvokeStatus.UnFound: + { + error = new error(); + error.code = -32601; + error.message = "函数未找到"; + break; + } + case InvokeStatus.UnEnable: + { + error = new error(); + error.code = -32601; + error.message = "函数已被禁用"; + break; + } + case InvokeStatus.InvocationException: + { + error = new error(); + error.code = -32603; + error.message = "函数内部异常"; + break; + } + case InvokeStatus.Exception: + { + error = new error(); + error.code = -32602; + error.message = invokeResult.Message; + break; + } + default: + return; + } + + Response(callContext, invokeResult.Result, error); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs.meta new file mode 100644 index 0000000..7f3cb9b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7710aeb895b8374380f5ce750dbf032 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc.meta new file mode 100644 index 0000000..e9b88b0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6e3c96546e137a49b6811efc81e4aed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute.meta new file mode 100644 index 0000000..5b8ddc9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c50400f0a5980114293e50407da0cdc9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs new file mode 100644 index 0000000..314fcf8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc方法标记属性类 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class TouchRpcAttribute : RpcAttribute + { + /// + /// 适用于TouchRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public TouchRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于TouchRpc的标记. + /// + /// + public TouchRpcAttribute(string invokenKey) + { + InvokeKey = invokenKey; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs.meta new file mode 100644 index 0000000..15d71b1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dddfbfce8e519cc48a0db068f773d6f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel.meta new file mode 100644 index 0000000..f913ea5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bedaa06e230693345a62affc77c271b2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs new file mode 100644 index 0000000..c0ac8b6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs @@ -0,0 +1,745 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 通道 + /// + [DebuggerDisplay("ID={ID},Status={Status}")] + public abstract class Channel : DisposableObject + { + /// + /// 是否具有数据可读 + /// + public abstract int Available { get; } + + /// + /// 缓存容量 + /// + public abstract int CacheCapacity { get; set; } + + /// + /// 判断当前通道能否调用 + /// + public abstract bool CanMoveNext { get; } + + /// + /// 能否写入 + /// + public abstract bool CanWrite { get; } + + /// + /// 通道ID + /// + public abstract int ID { get; } + + /// + /// 最后一次操作时显示消息 + /// + public abstract string LastOperationMes { get; } + + /// + /// 状态 + /// + public abstract ChannelStatus Status { get; } + + /// + /// 目的ID地址。仅当该通道由两个客户端打通时有效。 + /// + public abstract string TargetId { get; } + + /// + /// 超时时间,默认1000*10ms。 + /// + public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// 是否被使用 + /// + public abstract bool Using { get; } + + /// + /// 取消 + /// + public abstract void Cancel(string operationMes = null); + + /// + /// 异步取消 + /// + /// + public Task CancelAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + this.Cancel(operationMes); + }); + } + + /// + /// 完成操作 + /// + public abstract void Complete(string operationMes = null); + + /// + /// 异步完成操作 + /// + /// + public Task CompleteAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + this.Complete(operationMes); + }); + } + + /// + /// 获取当前的数据 + /// + public abstract byte[] GetCurrent(); + + /// + /// 继续。 + /// 调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用 + /// + /// + public abstract void HoldOn(string operationMes = null); + + /// + /// 异步调用继续 + /// + /// + /// + public Task HoldOnAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + this.HoldOn(operationMes); + }); + } + + /// + /// 转向下个元素 + /// + /// + public abstract bool MoveNext(); + + /// + /// 转向下个元素 + /// + /// + public Task MoveNextAsync() + { + return EasyTask.Run(() => + { + return this.MoveNext(); + }); + } + + /// + /// 阻塞读取数据,直到有数据,或者超时。 + /// + /// + public Task ReadAsync() + { + return EasyTask.Run(() => + { + if (this.MoveNext()) + { + return this.GetCurrent(); + } + return null; + }); + } + + /// + /// 尝试写入。 + /// + /// + /// + /// + /// + public bool TryWrite(byte[] data, int offset, int length) + { + if (this.CanWrite) + { + try + { + this.Write(data, offset, length); + return true; + } + catch + { + } + } + return false; + } + + /// + /// 尝试写入 + /// + /// + /// + public bool TryWrite(byte[] data) + { + return this.TryWrite(data, 0, data.Length); + } + + /// + /// 异步尝试写入 + /// + /// + /// + /// + /// + public async Task TryWriteAsync(byte[] data, int offset, int length) + { + if (this.CanWrite) + { + try + { + await this.WriteAsync(data, offset, length); + return true; + } + catch + { + } + } + return false; + } + + /// + /// 异步尝试写入 + /// + /// + /// + public Task TryWriteAsync(byte[] data) + { + return this.TryWriteAsync(data, 0, data.Length); + } + + /// + /// 写入通道 + /// + /// + /// + /// + public abstract void Write(byte[] data, int offset, int length); + + /// + /// 写入通道 + /// + /// + public void Write(byte[] data) + { + this.Write(data, 0, data.Length); + } + + /// + /// 写入通道 + /// + /// + /// + /// + public Task WriteAsync(byte[] data, int offset, int length) + { + return Task.Run(() => + { + this.Write(data, offset, length); + }); + } + + /// + /// 写入通道 + /// + /// + public void WriteAsync(byte[] data) + { + this.WriteAsync(data, 0, data.Length); + } + } + + internal class InternalChannel : Channel + { + private readonly RpcActor m_actor; + private readonly IntelligentDataQueue m_dataQueue; + private readonly AutoResetEvent m_moveWaitHandle; + private readonly string m_targetId; + private readonly Timer m_timer; + private int m_cacheCapacity; + private volatile bool m_canFree; + private byte[] m_currentData; + private int m_id; + private string m_lastOperationMes; + private DateTime m_lastOperationTime; + private ChannelStatus m_status; + private bool m_using; + + public InternalChannel(RpcActor client, string targetId) + { + this.m_actor = client; + this.m_lastOperationTime = DateTime.Now; + this.m_targetId = targetId; + this.m_status = ChannelStatus.Default; + this.m_cacheCapacity = 1024 * 1024 * 5; + this.m_dataQueue = new IntelligentDataQueue(this.m_cacheCapacity) + { + OverflowWait = false, + OnQueueChanged = OnQueueChanged + }; + this.m_moveWaitHandle = new AutoResetEvent(false); + this.m_canFree = true; + this.m_timer = new Timer((o) => + { + if (DateTime.Now - this.m_lastOperationTime > TimeSpan.FromTicks(this.Timeout.Ticks * 3)) + { + this.SafeDispose(); + } + }, null, 1000, 1000); + } + + /// + /// 析构函数 + /// + ~InternalChannel() + { + this.Dispose(false); + } + + /// + /// 是否具有数据可读 + /// + public override int Available => this.m_dataQueue.Count; + + /// + /// 缓存容量 + /// + public override int CacheCapacity + { + get => this.m_cacheCapacity; + set + { + if (value < 0) + { + value = 1024; + } + this.m_cacheCapacity = value; + this.m_dataQueue.MaxSize = value; + } + } + + /// + /// 判断当前通道能否调用 + /// + public override bool CanMoveNext + { + get + { + if (this.Available > 0) + { + return true; + } + if ((byte)this.m_status >= 4) + { + return false; + } + return true; + } + } + + /// + /// 能否写入 + /// + public override bool CanWrite => (byte)this.m_status <= 3; + + /// + /// ID + /// + public override int ID => this.m_id; + + /// + /// 最后一次操作时显示消息 + /// + public override string LastOperationMes + { + get => this.m_lastOperationMes; + } + + /// + /// 状态 + /// + public override ChannelStatus Status => this.m_status; + + /// + /// 目的ID地址。 + /// + public override string TargetId => this.m_targetId; + + /// + /// 是否被使用 + /// + public override bool Using => this.m_using; + + #region 操作 + + /// + /// 取消 + /// + public override void Cancel(string operationMes = null) + { + if ((byte)this.m_status > 3) + { + return; + } + try + { + this.RequestCancel(true); + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.CancelOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + catch + { + } + } + + /// + /// 完成操作 + /// + public override void Complete(string operationMes = null) + { + if ((byte)this.m_status > 3) + { + return; + } + + this.RequestComplete(true); + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.CompleteOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + + /// + /// 继续。 + /// 调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用 + /// + /// + public override void HoldOn(string operationMes = null) + { + if ((byte)this.m_status > 3) + { + return; + } + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.HoldOnOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + + + + try + { + this.m_timer.SafeDispose(); + this.RequestDispose(true); + + if ((byte)this.m_status > 3) + { + return; + } + + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.HoldOnOrder, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + catch + { + } + base.Dispose(disposing); + } + + #endregion 操作 + + /// + /// 获取当前的数据 + /// + public override byte[] GetCurrent() + { + return this.m_currentData; + } + + /// + /// 转向下个元素 + /// + /// + public override bool MoveNext() + { + if (!this.CanMoveNext) + { + return false; + } + if (this.m_dataQueue.TryDequeue(out ChannelPackage channelPackage)) + { + switch (channelPackage.DataType) + { + case ChannelDataType.DataOrder: + { + this.m_currentData = channelPackage.Data.Array; + return true; + } + case ChannelDataType.CompleteOrder: + this.RequestComplete(true); + return false; + + case ChannelDataType.CancelOrder: + this.RequestCancel(true); + return false; + + case ChannelDataType.DisposeOrder: + this.RequestDispose(true); + return false; + + case ChannelDataType.HoldOnOrder: + this.m_status = ChannelStatus.HoldOn; + return false; + + case ChannelDataType.QueueRun: + this.m_canFree = true; + return false; + + case ChannelDataType.QueuePause: + this.m_canFree = false; + return false; + + default: + return false; + } + } + + this.m_moveWaitHandle.Reset(); + if (this.m_moveWaitHandle.WaitOne(this.Timeout)) + { + return this.MoveNext(); + } + else + { + this.m_status = ChannelStatus.Overtime; + return false; + } + } + + /// + /// 写入通道 + /// + /// + /// + /// + public override void Write(byte[] data, int offset, int length) + { + if ((byte)this.m_status > 3) + { + throw new Exception($"通道已{this.m_status}"); + } + + if (!SpinWait.SpinUntil(() => { return this.m_canFree; }, this.Timeout)) + { + throw new TimeoutException(); + } + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + DataType = ChannelDataType.DataOrder, + Data = new ArraySegment(data, offset, length), + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + + internal void ReceivedData(ChannelPackage channelPackage) + { + this.m_lastOperationTime = DateTime.Now; + if (channelPackage.RunNow) + { + switch (channelPackage.DataType) + { + case ChannelDataType.CompleteOrder: + this.m_lastOperationMes = channelPackage.Message; + this.RequestComplete(false); + break; + + case ChannelDataType.CancelOrder: + this.m_lastOperationMes = channelPackage.Message; + this.RequestCancel(false); + break; + + case ChannelDataType.DisposeOrder: + this.RequestDispose(false); + break; + + case ChannelDataType.HoldOnOrder: + this.m_lastOperationMes = channelPackage.Message; + this.m_status = ChannelStatus.HoldOn; + break; + + case ChannelDataType.QueueRun: + this.m_canFree = true; + return; + + case ChannelDataType.QueuePause: + this.m_canFree = false; + return; + + default: + return; + } + } + this.m_dataQueue.Enqueue(channelPackage); + this.m_moveWaitHandle.Set(); + } + + internal void SetID(int id) + { + this.m_id = id; + } + + internal void SetUsing() + { + this.m_using = true; + } + + private void Clear() + { + try + { + lock (this) + { + this.m_dataQueue.Clear(); + if (this.m_actor.RemoveChannel(this.m_id)) + { + this.m_moveWaitHandle.Set(); + this.m_moveWaitHandle.SafeDispose(); + } + } + } + catch + { + } + } + + private void OnQueueChanged(bool free) + { + if ((byte)this.m_status > 3) + { + return; + } + + try + { + var channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = free ? ChannelDataType.QueueRun : ChannelDataType.QueuePause, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + this.m_lastOperationTime = DateTime.Now; + } + catch + { + } + } + + private void RequestCancel(bool clear) + { + this.m_status = ChannelStatus.Cancel; + if (clear) + { + this.Clear(); + } + } + + private void RequestComplete(bool clear) + { + this.m_status = ChannelStatus.Completed; + if (clear) + { + this.Clear(); + } + } + + internal void RequestDispose(bool clear) + { + if (clear) + { + this.Clear(); + } + if ((byte)this.m_status > 3) + { + return; + } + this.m_status = ChannelStatus.Disposed; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs.meta new file mode 100644 index 0000000..2c6c06a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d5f70a886acd15468c96b3bcfdaff6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs new file mode 100644 index 0000000..9e411bc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal enum ChannelDataType : byte + { + DataOrder, + CompleteOrder, + CancelOrder, + DisposeOrder, + HoldOnOrder, + QueueRun, + QueuePause + } + + internal class ChannelPackage : MsgRouterPackage, IQueueData + { + public int ChannelId { get; set; } + public ArraySegment Data { get; set; } + public ChannelDataType DataType { get; set; } + public bool RunNow { get; set; } + int IQueueData.Size => this.Data == null ? 0 : this.Data.Count; + + public int GetLen() + { + if (Data == null) + { + return 1024; + } + return Data.Count + 1024; + } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(RunNow); + byteBlock.Write((byte)DataType); + byteBlock.Write(ChannelId); + byteBlock.WriteBytesPackage(Data.Array, Data.Offset, Data.Count); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.RunNow = byteBlock.ReadBoolean(); + this.DataType = (ChannelDataType)byteBlock.ReadByte(); + this.ChannelId = byteBlock.ReadInt32(); + var data = byteBlock.ReadBytesPackage(); + if (data != null) + { + this.Data = new ArraySegment(data); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs.meta new file mode 100644 index 0000000..eab3f9c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 85244f5da5798544d9fe3dc95ceba7ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs new file mode 100644 index 0000000..b7db940 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 通道状态 + /// + public enum ChannelStatus : byte + { + /// + /// 默认 + /// + Default = 0, + + /// + /// 继续下移 + /// + Moving = 1, + + /// + /// 超时 + /// + Overtime = 2, + + /// + /// 继续 + /// + HoldOn = 3, + + /// + /// 取消 + /// + Cancel = 4, + + /// + /// 完成 + /// + Completed = 5, + + /// + /// 已释放 + /// + Disposed = 6 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs.meta new file mode 100644 index 0000000..45a40eb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80d71a80e5499854c9e39223eaaffb6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs new file mode 100644 index 0000000..0ac6bc6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// WaitCreateChannel + /// + internal class WaitCreateChannelPackage : WaitRouterPackage + { + /// + /// 随机ID + /// + public bool Random { get; set; } + + /// + /// 通道ID + /// + public int ChannelID { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Random); + byteBlock.Write(ChannelID); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.Random = byteBlock.ReadBoolean(); + this.ChannelID = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs.meta new file mode 100644 index 0000000..bb951b7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6067db9adf588a49bfd4abb9df9d76e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common.meta new file mode 100644 index 0000000..e9da7ad --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6709fa57cf5eadd43add402313444e10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs new file mode 100644 index 0000000..16d4a1a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 关于具有流速的操作器。 + /// + public abstract class FlowOperator + { + /// + /// 已完成长度 + /// + protected long completedLength; + + /// + /// 进度 + /// + protected float m_progress; + + private long m_speed; + private long m_speedTemp; + + /// + /// 已完成长度 + /// + /// + public long CompletedLength { get => completedLength; } + + /// + /// 由的结果,判断是否已结束操作。 + /// + public virtual bool IsEnd { get => Result.ResultCode != ResultCode.Default; } + + /// + /// 数据源的全部长度。 + /// + public long Length { get; protected set; } + + /// + /// 最大传输速度。 + /// + public int MaxSpeed { get; protected set; } = int.MaxValue; + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 进度 + /// + public float Progress => m_progress; + + /// + /// 执行结果 + /// + public Result Result { get; protected set; } + + /// + /// 超时时间,默认10*1000ms。 + /// + public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// 可取消令箭 + /// + public CancellationToken Token { get; set; } + + /// + /// 从上次获取到此次获得的速度 + /// + /// + public long Speed() + { + m_speed = m_speedTemp; + m_speedTemp = 0; + return m_speed; + } + + internal void SetLength(long len) + { + Length = len; + } + + /// + /// 设置结果状态 + /// + /// + /// + internal Result SetResult(Result result) + { + Result = result; + return result; + } + + /// + /// 添加流速(线程安全) + /// + /// + protected internal virtual void AddFlow(int flow) + { + Interlocked.Add(ref m_speedTemp, flow); + m_progress = (float)((double)Interlocked.Add(ref completedLength, flow) / Length); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs.meta new file mode 100644 index 0000000..ccfa666 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3dbd5a0292f1074492bad88368fc02a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface.meta new file mode 100644 index 0000000..6e3929d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0dd2b99af6c10a42b6b87cc7b198ae8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs new file mode 100644 index 0000000..f820795 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IDependencyTouchRpc + /// + public interface IDependencyTouchRpc : ITouchRpc, IDependencyObject + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs.meta new file mode 100644 index 0000000..ec6a851 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2408b2d2aa9c29d4fa4fcd73f6aeb076 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs new file mode 100644 index 0000000..5c6fcdb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpc + /// + public interface ITouchRpc : IRpcActor + { + /// + /// Rpc执行角色 + /// + RpcActor RpcActor { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs.meta new file mode 100644 index 0000000..3b2b950 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c3214821df36914e8af082241bb8d82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs new file mode 100644 index 0000000..24ee4b1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcCallContext + /// + public interface ITouchRpcCallContext : ICallContext + { + /// + /// 当不为空时,调用 + /// + /// + public bool TryCancel(); + + /// + /// TouchRpcContext + /// + TouchRpcPackage TouchRpcPackage { get; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs.meta new file mode 100644 index 0000000..8fc263a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d1f6b6400193374d94d07baeb1094b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs new file mode 100644 index 0000000..65b282d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcService + /// + public interface ITouchRpcService : IRpcParser, ITargetRpcActor + { + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 协议 + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string targetId, short protocol, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 协议 + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string targetId, short protocol, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs.meta new file mode 100644 index 0000000..d026e34 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08d78f2e6a735d74395d8b0b3a0505ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs new file mode 100644 index 0000000..f1a23c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs @@ -0,0 +1,281 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcUtility + /// + public partial class TouchRpcUtility + { + /// + /// TouchRpc字符串 + /// + public const string TouchRpc = "TOUCHRPC"; + + /// + /// TouchRpc + /// + public static Protocol TouchRpcProtocol { get; private set; } = new Protocol(TouchRpc); + + /// + /// 传输分包 + /// + public const int TransferPackage = 1024 * 512; + + #region 基本协议,0-99; + + /// + /// 握手 + /// + public const short P_0_Handshake_Request = 0; + + /// + /// 重置ID + /// + public const short P_1_ResetID_Request = -1; + + /// + /// 握手响应 + /// + public const short P_1000_Handshake_Response = -1000; + + /// + /// 重置ID响应 + /// + public const short P_1001_ResetID_Response = -1001; + + /// + /// Ping回应 + /// + public const short P_1002_Ping_Response = -1002; + + /// + /// Ping + /// + public const short P_2_Ping_Request = -2; + + #endregion 基本协议,0-99; + + #region 通道协议,100-199; + + /// + /// 创建一个面向对方的通道 + /// + public const short P_100_CreateChannel_Request = -100; + + /// + /// 创建通道回应 + /// + public const short P_1100_CreateChannel_Response = -1100; + + /// + /// 通道数据 + /// + public const short P_101_ChannelPackage = -101; + + #endregion 通道协议,100-199; + + #region Rpc协议,200-299; + + /// + /// 调用响应 + /// + public const short P_1200_Invoke_Response = -1200; + + ///// + ///// 调用ID客户端响应 + ///// + //public const short P_1201_Invoke2C_Response = -1201; + + /// + /// 调用 + /// + public const short P_200_Invoke_Request = -200; + + ///// + ///// 调用ID客户端 + ///// + //public const short P_201_Invoke2C_Request = -201; + + /// + /// 取消调用 + /// + public const short P_204_CancelInvoke = -204; + + ///// + ///// 取消调用 + ///// + //public const short P_205_CancelInvoke2C = -205; + + #endregion Rpc协议,200-299; + + #region Stream协议 400-499 + + /// + /// 向服务器发送流响应 + /// + public const short P_1400_SendStreamToSocketClient_Response = -1400; + + /// + /// 向服务器发送流 + /// + public const short P_400_SendStreamToSocketClient_Request = -400; + + /// + /// 向客户端发送流 + /// + public const short P_401_SendStreamToClient = -401; + + #endregion Stream协议 400-499 + + #region FileTransfer协议 500-599 + + /// + /// 拉取文件响应 + /// + public const short P_1500_PullFile_Response = -1500; + + /// + /// 开始拉取文件响应 + /// + public const short P_1501_BeginPullFile_Response = -1501; + + /// + /// 推送文件响应 + /// + public const short P_1502_PushFile_Response = -1502; + + ///// + ///// 从客户端拉取文件响应 + ///// + //public const short P_1503_PullFile2C_Response = -1503; + + ///// + ///// 客户端拉取文件转发响应 + ///// + //public const short P_1504_PullFileFC_Response = -1504; + + ///// + ///// 开始从客户端拉取文件响应 + ///// + //public const short P_1505_BeginPullFile2C_Response = -1505; + + ///// + ///// 开始从客户端拉取文件转发响应 + ///// + //public const short P_1506_BeginPullFileFC_Response = -1506; + + ///// + ///// 推送到客户端响应 + ///// + //public const short P_1507_PushFile2C_Response = -1507; + + ///// + ///// 推送到客户端转发响应 + ///// + //public const short P_1508_PushFileFC_Response = -1508; + + /// + /// 拉取文件 + /// + public const short P_500_PullFile_Request = -500; + + /// + /// 开始拉取文件 + /// + public const short P_501_BeginPullFile_Request = -501; + + /// + /// 推送文件 + /// + public const short P_502_PushFile_Request = -502; + + ///// + ///// 从客户端拉取文件 + ///// + //public const short P_503_PullFile2C_Request = -503; + + ///// + ///// 客户端拉取文件转发 + ///// + //public const short P_504_PullFileFC_Request = -504; + + ///// + ///// 开始从客户端拉取文件 + ///// + //public const short P_505_BeginPullFile2C_Request = -505; + + ///// + ///// 开始从客户端拉取文件转发 + ///// + //public const short P_506_BeginPullFileFC_Request = -506; + + ///// + ///// 推送到客户端 + ///// + //public const short P_507_PushFile2C_Request = -507; + + ///// + ///// 推送到客户端转发 + ///// + //public const short P_508_PushFileFC_Request = -508; + + /// + /// 推送文件状态确认 + /// + public const short P_509_PushFileAck_Request = -509; + + ///// + ///// 推送文件到客户端状态确认 + ///// + //public const short P_511_PushFileAck2C_Request = -511; + + /// + /// 拉取小文件请求 + /// + public const short P_517_PullSmallFile_Request = -517; + + /// + /// 拉取确认小文件响应 + /// + public const short P_1517_PullSmallFile_Response = -1517; + + /// + /// 推送小文件请求 + /// + public const short P_518_PushSmallFile_Request = -518; + + /// + /// 推送确认小文件响应 + /// + public const short P_1518_PushSmallFile_Response = -1518; + + #endregion FileTransfer协议 500-599 + + #region Redis 600-699 + + /// + /// Redis + /// + public const short P_600_Redis_Request = -600; + + /// + /// Redis回应 + /// + public const short P_1600_Redis_Response = -1600; + + #endregion Redis 600-699 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs.meta new file mode 100644 index 0000000..4d2ad28 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 67679b3123a1d32459bac0f4423d8598 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs new file mode 100644 index 0000000..130e5bd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitPingPackage : WaitRouterPackage + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs.meta new file mode 100644 index 0000000..261699c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5674303b42e48834086bb91637bd4df4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs new file mode 100644 index 0000000..7e3ba1d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 设置ID + /// + public class WaitSetID : WaitResult + { + /// + /// 重置Id + /// + public WaitSetID() + { + } + + /// + /// 构造函数 + /// + /// + /// + public WaitSetID(string oldID, string newID) + { + OldID = oldID; + NewID = newID; + } + + /// + /// 旧ID + /// + public string OldID { get; set; } + + /// + /// 新ID + /// + public string NewID { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs.meta new file mode 100644 index 0000000..d56464f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f83269f1e38882f4a991c55b2f6136b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs new file mode 100644 index 0000000..ea4fbcd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 验证消息 + /// + public class WaitVerify : WaitResult + { + /// + /// 令箭 + /// + public string Token { get; set; } + + internal bool Handle { get; set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// ID + /// + public string ID { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs.meta new file mode 100644 index 0000000..98c2a7b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b04a94e3655650b46815b74b6c4ffb50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components.meta new file mode 100644 index 0000000..2a45717 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 223fc5aab03e9df4e995a93a8e87596b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http.meta new file mode 100644 index 0000000..aed988f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1a9547e3e3003b49a7682b93184124f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs new file mode 100644 index 0000000..286306e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs @@ -0,0 +1,627 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// HttpRpcClient + /// + public partial class HttpTouchRpcClient : HttpClientBase, IHttpTouchRpcClient + { + private readonly ActionMap m_actionMap; + private readonly RpcActor m_rpcActor; + private RpcStore m_rpcStore; + + /// + /// 创建一个HttpTouchRpcClient实例。 + /// + public HttpTouchRpcClient() + { + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnHandshaked = OnRpcActorHandshaked, + OnRouting = OnRpcActorRouting, + OnReceived = OnRpcActorReceived, + OnClose = OnRpcServiceClose, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + GetInvokeMethod = GetInvokeMethod, + Caller = this + }; + } + + /// + /// 服务器映射 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor != null && m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public override ITcpClient Connect(int timeout = 5000) + { + lock (SyncRoot) + { + if (IsHandshaked) + { + return this; + } + if (!Online) + { + base.Connect(timeout); + } + HttpRequest httpRequest = new HttpRequest(); + httpRequest.InitHeaders() + .AsMethod(TouchRpcUtility.TouchRpc); + var response = RequestContent(httpRequest); + if (response.StatusCode == "200") + { + this.SwitchProtocolToTouchRpc(); + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + return this; + } + else + { + throw new Exception(response.StatusMessage); + } + } + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public void ResetID(string newId) + { + m_rpcActor.ResetID(newId); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (Protocol == TouchRpcUtility.TouchRpcProtocol && byteBlock != null) + { + m_rpcActor.InputReceivedData(byteBlock); + return; + } + base.HandleReceivedData(byteBlock, requestInfo); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor?.Close(e.Message); + base.OnDisconnected(e); + } + + #region 小文件 + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + #endregion 小文件 + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return ActionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + #endregion 内部委托绑定 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(MsgEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs.meta new file mode 100644 index 0000000..09f0c9a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34587e423eb82df43a94293ed3ed6167 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs new file mode 100644 index 0000000..9d31cab --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs @@ -0,0 +1,602 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http Rpc解释器 + /// + public class HttpTouchRpcService : HttpTouchRpcService + { + } + + /// + /// HttpRpcParser泛型类型 + /// + /// + public partial class HttpTouchRpcService : HttpService, IHttpTouchRpcService where TClient : HttpTouchRpcSocketClient + { + /// + /// 创建一个HttpTouchRpcService实例。 + /// + public HttpTouchRpcService() + { + m_actionMap = new ActionMap(); + m_rpcActorGroup = new RpcActorGroup + { + OnClose = OnRpcServiceClose, + OnRouting = OnRpcServiceRouting, + GetInvokeMethod = GetInvokeMethod, + OnFileTransfered = OnRpcServiceFileTransfered, + OnFileTransfering = OnRpcServiceFileTransfering, + OnFindRpcActor = OnRpcServiceFindRpcActor, + OnHandshaked = OnRpcServiceHandshaked, + OnHandshaking = OnRpcServiceHandshaking, + OnReceived = OnRpcServiceReceived, + OnStreamTransfered = OnRpcServiceStreamTransfered, + OnStreamTransfering = OnRpcServiceStreamTransfering, + OutputSend = RpcServiceOutputSend + }; + } + + #region 字段 + + private readonly ActionMap m_actionMap; + private readonly RpcActorGroup m_rpcActorGroup; + private RpcStore m_rpcStore; + + #endregion 字段 + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActorGroup.Config = config; + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + /// + protected override void OnConnecting(TClient socketClient, OperationEventArgs e) + { + socketClient.m_internalOnRpcActorInit = PrivateOnRpcActorInit; + base.OnConnecting(socketClient, e); + } + + #region 事件 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual void OnReceived(TClient client, short protocol, ByteBlock byteBlock) + { + } + + /// + /// 在需要转发路由包时。 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + private void PrivateOnRpcActorInit(HttpTouchRpcSocketClient client) + { + client.SetRpcActor(m_rpcActorGroup.CreateRpcActor(client)); + } + + #endregion 事件 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFile(path, metadata, timeout, token); + } + else + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFileAsync(path, metadata, timeout, token); + } + else + { + return Task.FromResult(new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + else + { + return Task.FromResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + #endregion 小文件 + + #region Rpc + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Ping(timeout); + } + return false; + } + + #endregion Rpc + + #region 通道 + + /// + public Channel CreateChannel(string targetId) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(id); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 通道 + + #region File + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion File + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + TClient client = (TClient)actor.Caller; + client.Close(arg2); + } + + private void OnRpcServiceFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), client, e)) + { + return; + } + OnFileTransfered(client, e); + } + + private void OnRpcServiceFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), client, e)) + { + return; + } + OnFileTransfering(client, e); + } + + private RpcActor OnRpcServiceFindRpcActor(string arg) + { + if (TryGetSocketClient(arg, out TClient client)) + { + return client.RpcActor; + } + return null; + } + + private void OnRpcServiceHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), client, e)) + { + return; + } + OnHandshaked(client, e); + } + + private void OnRpcServiceHandshaking(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (e.Token == VerifyToken) + { + e.IsPermitOperation = true; + } + else + { + e.Message = "Token不受理"; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaking), client, e)) + { + return; + } + OnHandshaking(client, e); + } + + + private void OnRpcServiceReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), client, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(client, protocol, byteBlock); + } + + private void OnRpcServiceRouting(RpcActor actor, PackageRouterEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), client, e)) + { + return; + } + OnRouting(client, e); + } + + private void OnRpcServiceStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), client, e)) + { + return; + } + OnStreamTransfered(client, e); + } + + private void OnRpcServiceStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), client, e)) + { + return; + } + OnStreamTransfering(client, e); + } + + private void RpcServiceOutputSend(RpcActor actor, ArraySegment[] arg3) + { + TClient client = (TClient)actor.Caller; + client.RpcActorSend(arg3); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActorGroup.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 发送 + + /// + public void Send(string id, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out TClient client)) + { + client.Send(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + public Task SendAsync(string id, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out TClient client)) + { + return client.SendAsync(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs.meta new file mode 100644 index 0000000..8cc93a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7344815235741f428c1b608b2d9e43d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs new file mode 100644 index 0000000..ad5b8d9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs @@ -0,0 +1,429 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http服务器辅助类 + /// + public partial class HttpTouchRpcSocketClient : HttpSocketClient, IHttpTouchRpcSocketClient + { + internal Action m_internalOnRpcActorInit; + private RpcActor m_rpcActor; + + /// + public bool IsHandshaked => m_rpcActor == null ? false : m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public override void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + DirectResetID(newID); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + internal void RpcActorSend(ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + internal void SetRpcActor(RpcActor rpcActor) + { + m_rpcActor = rpcActor; + m_rpcActor.OnResetID = ThisOnResetID; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (Protocol == TouchRpcUtility.TouchRpcProtocol && byteBlock != null) + { + m_rpcActor.InputReceivedData(byteBlock); + } + else + { + base.HandleReceivedData(byteBlock, requestInfo); + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor?.Close(e.Message); + base.OnDisconnected(e); + } + + /// + /// + /// + /// + protected override void OnReceivedHttpRequest(HttpRequest request) + { + if (request.Method == TouchRpcUtility.TouchRpc) + { + request.SafeDispose(); + InitRpcActor(); + this.DefaultSend(new HttpResponse().SetStatus().BuildAsBytes()); + return; + } + base.OnReceivedHttpRequest(request); + } + + private void InitRpcActor() + { + this.SwitchProtocolToTouchRpc(); + m_internalOnRpcActorInit?.Invoke(this); + m_rpcActor.ID = ID; + } + + private void ThisOnResetID(bool first, RpcActor rpcActor, WaitSetID waitSetID) + { + DirectResetID(waitSetID.NewID); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs.meta new file mode 100644 index 0000000..1cfc7e8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cbcf2f49dd284434f93d2e901e95e514 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface.meta new file mode 100644 index 0000000..4c1f992 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c8279a6f4c0ae74e8e39c0d7b8aba85 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs new file mode 100644 index 0000000..3745d8d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IHttpRpcClient + /// + public interface IHttpTouchRpcClient : IHttpClient, IHttpRpcClientBase, IRpcParser + { + } + + /// + /// IHttpTouchRpcSocketClient + /// + public interface IHttpTouchRpcSocketClient : IHttpRpcClientBase + { + } + + /// + /// IHttpRpcClientBase + /// + public interface IHttpRpcClientBase : IHttpClientBase, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs.meta new file mode 100644 index 0000000..054f785 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77929d582e3e7c542b8cc8088fe43fd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs new file mode 100644 index 0000000..6232fb2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IHttpTouchRpcService + /// + public interface IHttpTouchRpcService : IHttpService, ITouchRpcService + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs.meta new file mode 100644 index 0000000..e07cd4d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2df9a136502fa2c4cb371f994e7ff64c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs new file mode 100644 index 0000000..739847d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorGroup + /// + public partial class RpcActorGroup + { + #region 委托 + + /// + /// 获取调用函数 + /// + public Func GetInvokeMethod { get; set; } + + /// + /// 请求关闭 + /// + public Action OnClose { get; set; } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + public Action OnFileTransfered { get; set; } + + /// + /// 在文件传输即将进行时触发。 + /// + public Action OnFileTransfering { get; set; } + + /// + /// 查找其他RpcActor + /// + public Func OnFindRpcActor { get; set; } + + /// + /// 在完成握手连接时 + /// + public Action OnHandshaked { get; set; } + + /// + /// 握手 + /// + public Action OnHandshaking { get; set; } + + /// + /// 接收到数据 + /// + public Action OnReceived { get; set; } + + /// + /// 需要路由 + /// + public Action OnRouting { get; set; } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + public Action OnStreamTransfered { get; set; } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + public Action OnStreamTransfering { get; set; } + + /// + /// 发送数据接口 + /// + public Action[]> OutputSend { get; set; } + + #endregion 委托 + + /// + /// 配置 + /// + public TouchSocketConfig Config { get; set; } + + /// + /// RpcStore + /// + public RpcStore RpcStore { get; set; } + + /// + /// 创建RpcActor + /// + /// + /// + public RpcActor CreateRpcActor(object caller) + { + RpcActor rpcActor = new RpcActor(true) + { + FileController = this.Config.Container.GetFileResourceController(), + Logger = Config.Container.Resolve(), + Caller = caller, + RpcStore = RpcStore, + OnHandshaking = OnHandshaking, + GetInvokeMethod = GetInvokeMethod, + OnHandshaked = OnHandshaked, + OutputSend = OutputSend, + OnReceived = OnReceived, + OnClose = OnClose, + OnFindRpcActor = OnFindRpcActor, + OnRouting = OnRouting, + OnStreamTransfering = OnStreamTransfering, + OnStreamTransfered = OnStreamTransfered, + OnFileTransfering = OnFileTransfering, + OnFileTransfered = OnFileTransfered, + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty), + SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty) + }; + return rpcActor; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs.meta new file mode 100644 index 0000000..a3d42e3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d770b5136e3f3ee4d9e50ed4af8ebfc3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp.meta new file mode 100644 index 0000000..aa723d4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: deee777be9b22a34bade36502f9b2af8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface.meta new file mode 100644 index 0000000..6aa9ed6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b9ff671a6299104292d2e3710a0c393 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs new file mode 100644 index 0000000..5c751b6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITcpRpcClient + /// + public interface ITcpTouchRpcClient : ITcpRpcClientBase, ITcpClient, IRpcParser + { + } + + /// + /// ITcpTouchRpcSocketClient + /// + public interface ITcpTouchRpcSocketClient : ITcpRpcClientBase + { + } + + /// + /// ITcpRpcClientBase + /// + public interface ITcpRpcClientBase : ITcpClientBase, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs.meta new file mode 100644 index 0000000..d8aef80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20f9b407c295324459bd36355d9e706a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs new file mode 100644 index 0000000..ca15128 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITcpTouchRpcService + /// + public interface ITcpTouchRpcService : ITcpService, ITouchRpcService + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs.meta new file mode 100644 index 0000000..e51028d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff3a4839b3472e24683f77de8017292e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs new file mode 100644 index 0000000..e7589be --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs @@ -0,0 +1,625 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TcpTouchRpcClient + /// + public partial class TcpTouchRpcClient : TcpClientBase, ITcpTouchRpcClient + { + private readonly ActionMap m_actionMap; + + private readonly RpcActor m_rpcActor; + + private RpcStore m_rpcStore; + + /// + /// 创建一个TcpTouchRpcClient实例。 + /// + public TcpTouchRpcClient() + { + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnRouting = OnRpcActorRouting, + OnHandshaked = OnRpcActorHandshaked, + OnReceived = OnRpcActorReceived, + OnClose = OnRpcServiceClose, + GetInvokeMethod = GetInvokeMethod, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + Caller = this + }; + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor == null ? false : m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + /// 建立Tcp连接,并且执行握手。 + /// + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + lock (SyncRoot) + { + if (IsHandshaked) + { + return this; + } + if (!Online) + { + base.Connect(timeout); + } + + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + return this; + } + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public void ResetID(string id) + { + m_rpcActor.ResetID(id); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + m_rpcActor.InputReceivedData(byteBlock); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + RootPath = config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + + this.SwitchProtocolToTouchRpc(); + } + + /// + protected override void OnConnecting(ConnectingEventArgs e) + { + SetDataHandlingAdapter(new FixedHeaderPackageAdapter()); + base.OnConnecting(e); + } + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor.Close(e.Message); + base.OnDisconnected(e); + } + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(VerifyOptionEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs.meta new file mode 100644 index 0000000..710e192 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 385e21f3e6f55674c8364730da82b9ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs new file mode 100644 index 0000000..e563496 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs @@ -0,0 +1,598 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TcpTouchRpcService + /// + public class TcpTouchRpcService : TcpTouchRpcService + { + } + + /// + /// TcpTouchRpcService泛型类型 + /// + /// + public partial class TcpTouchRpcService : TcpService, ITcpTouchRpcService where TClient : TcpTouchRpcSocketClient + { + /// + /// 创建一个TcpTouchRpcService实例。 + /// + public TcpTouchRpcService() + { + m_actionMap = new ActionMap(); + m_rpcActorGroup = new RpcActorGroup + { + OnClose = OnRpcServiceClose, + OnRouting = OnRpcServiceRouting, + GetInvokeMethod = GetInvokeMethod, + OnFileTransfered = OnRpcServiceFileTransfered, + OnFileTransfering = OnRpcServiceFileTransfering, + OnFindRpcActor = OnRpcServiceFindRpcActor, + OnHandshaked = OnRpcServiceHandshaked, + OnHandshaking = OnRpcServiceHandshaking, + OnReceived = OnRpcServiceReceived, + OnStreamTransfered = OnRpcServiceStreamTransfered, + OnStreamTransfering = OnRpcServiceStreamTransfering, + OutputSend = RpcServiceOutputSend + }; + } + + #region 字段 + + private readonly ActionMap m_actionMap; + private readonly RpcActorGroup m_rpcActorGroup; + private RpcStore m_rpcStore; + + #endregion 字段 + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActorGroup.Config = config; + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + /// + /// 客户端请求连接 + /// + /// + /// + protected override void OnConnecting(TClient socketClient, OperationEventArgs e) + { + socketClient.SetRpcActor(m_rpcActorGroup.CreateRpcActor(socketClient)); + base.OnConnecting(socketClient, e); + } + + #region 事件 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 在需要转发路由包时。 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual void OnReceived(TClient client, short protocol, ByteBlock byteBlock) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + #endregion 事件 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFile(path, metadata, timeout, token); + } + else + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFileAsync(path, metadata, timeout, token); + } + else + { + return Task.FromResult(new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + else + { + return Task.FromResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + #endregion 小文件 + + #region Rpc + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Ping(timeout); + } + return false; + } + + #endregion Rpc + + #region 通道 + + /// + public Channel CreateChannel(string targetId) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(id); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 通道 + + #region File + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion File + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + TClient client = (TClient)actor.Caller; + client.Close(arg2); + } + + private void OnRpcServiceRouting(RpcActor actor, PackageRouterEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), client, e)) + { + return; + } + OnRouting(client, e); + } + + private void OnRpcServiceFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), client, e)) + { + return; + } + OnFileTransfered(client, e); + } + + private void OnRpcServiceFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), client, e)) + { + return; + } + OnFileTransfering(client, e); + } + + private RpcActor OnRpcServiceFindRpcActor(string arg) + { + if (TryGetSocketClient(arg, out TClient client)) + { + return client.RpcActor; + } + return null; + } + + private void OnRpcServiceHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), client, e)) + { + return; + } + OnHandshaked(client, e); + } + + private void OnRpcServiceHandshaking(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (e.Token == VerifyToken) + { + e.IsPermitOperation = true; + } + else + { + e.Message = "Token不受理"; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaking), client, e)) + { + return; + } + OnHandshaking(client, e); + } + + private void OnRpcServiceReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), client, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(client, protocol, byteBlock); + } + + private void OnRpcServiceStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), client, e)) + { + return; + } + OnStreamTransfered(client, e); + } + + private void OnRpcServiceStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), client, e)) + { + return; + } + OnStreamTransfering(client, e); + } + + private void RpcServiceOutputSend(RpcActor actor, ArraySegment[] arg3) + { + TClient client = (TClient)actor.Caller; + client.RpcActorSend(arg3); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActorGroup.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 发送 + + /// + public void Send(string targetId, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(targetId, out TClient client)) + { + client.Send(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task SendAsync(string targetId, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(targetId, out TClient client)) + { + return client.SendAsync(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs.meta new file mode 100644 index 0000000..7cc0451 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f44aa5a33ed4f804e849865783689b7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs new file mode 100644 index 0000000..77820d7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs @@ -0,0 +1,407 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc服务器辅助类 + /// + public partial class TcpTouchRpcSocketClient : SocketClient, ITcpTouchRpcSocketClient + { + private RpcActor m_rpcActor; + + /// + public bool IsHandshaked => m_rpcActor != null && m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + /// 验证超时时间,默认为3000ms + /// + public int VerifyTimeout => Config.GetValue(TouchRpcConfigExtensions.VerifyTimeoutProperty); + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public override void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + DirectResetID(newID); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + internal void RpcActorSend(ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + internal void SetRpcActor(RpcActor rpcActor) + { + m_rpcActor = rpcActor; + m_rpcActor.OnResetID = ThisOnResetID; + } + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + m_rpcActor.InputReceivedData(byteBlock); + } + + /// + protected override void OnConnected(TouchSocketEventArgs e) + { + EasyTask.DelayRun(VerifyTimeout, this, (client) => + { + if (!client.IsHandshaked) + { + client.Close("验证超时"); + } + }); + m_rpcActor.ID = ID; + base.OnConnected(e); + } + + /// + protected override void OnConnecting(OperationEventArgs e) + { + this.SwitchProtocolToTouchRpc(); + base.OnConnecting(e); + } + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor.Close(e.Message); + base.OnDisconnected(e); + } + + private void ThisOnResetID(bool first, RpcActor rpcActor, WaitSetID waitSetID) + { + DirectResetID(waitSetID.NewID); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs.meta new file mode 100644 index 0000000..201b4fb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 341fe8738a11bd84399606afdf6d24a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp.meta new file mode 100644 index 0000000..aba9af8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0548e6f03a2dea14c981e1c7c4fd3deb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface.meta new file mode 100644 index 0000000..246eabb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a605a4af238a34c4ab2d85cd518b4118 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs new file mode 100644 index 0000000..60fd923 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IUdpTouchRpc + /// + public interface IUdpTouchRpc : IUdpSession, IRpcParser, IRpcClient, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs.meta new file mode 100644 index 0000000..497cd91 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f233188cbfb0f641866f0607576b853 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs new file mode 100644 index 0000000..15f39a7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs @@ -0,0 +1,385 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// UDP Rpc解释器 + /// + public partial class UdpTouchRpc : UdpSessionBase, IUdpTouchRpc + { + private readonly ActionMap m_actionMap; + private readonly Timer m_timer; + private readonly ConcurrentDictionary m_udpRpcActors; + private RpcStore m_rpcStore; + private SerializationSelector m_serializationSelector; + + /// + /// 构造函数 + /// + public UdpTouchRpc() + { + m_timer = new Timer((obj) => + { + m_udpRpcActors.Remove((kv) => + { + if (--kv.Value.Tick < 0) + { + return true; + } + return false; + }); + }, null, 1000 * 30, 1000 * 30); + m_actionMap = new ActionMap(); + m_udpRpcActors = new ConcurrentDictionary(); + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + /// 不需要握手,所以此值一直为True。 + /// + public bool IsHandshaked => true; + + string IRpcActor.RootPath { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + /// + public RpcActor RpcActor => GetUdpRpcActor(); + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_serializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + bool IRpcActor.ChannelExisted(int id) + { + throw new NotImplementedException(); + } + + Channel IRpcActor.CreateChannel() + { + throw new NotImplementedException(); + } + + Channel IRpcActor.CreateChannel(int id) + { + throw new NotImplementedException(); + } + + Channel ITargetRpcActor.CreateChannel(string targetId) + { + throw new NotImplementedException(); + } + + Channel ITargetRpcActor.CreateChannel(string targetId, int id) + { + throw new NotImplementedException(); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + GetUdpRpcActor().Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return GetUdpRpcActor().Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + GetUdpRpcActor().Invoke(method, invokeOption, ref parameters, types); + } + + void ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + T ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + void ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + throw new NotImplementedException(); + } + + T ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + throw new NotImplementedException(); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().InvokeAsync(method, invokeOption, parameters); + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + Task ITargetRpcClient.InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + Task ITargetRpcClient.InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + /// + public bool Ping(int timeout = 5000) + { + return GetUdpRpcActor().Ping(timeout); + } + + bool ITargetRpcActor.Ping(string targetId, int timeout) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PullFile(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PullFile(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PullFileAsync(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PullFileAsync(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + PullSmallFileResult IRpcActor.PullSmallFile(string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + PullSmallFileResult ITargetRpcActor.PullSmallFile(string targetId, string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PullSmallFileAsync(string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PullSmallFileAsync(string targetId, string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PushFile(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PushFile(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PushFileAsync(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PushFileAsync(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + void IRpcActor.ResetID(string newID) + { + throw new NotImplementedException(); + } + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + GetUdpRpcActor().Send(protocol, buffer, offset, length); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return GetUdpRpcActor().SendAsync(protocol, buffer, offset, length); + } + + Result IRpcActor.SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata) + { + throw new NotImplementedException(); + } + + Task IRpcActor.SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata) + { + throw new NotImplementedException(); + } + + bool IRpcActor.TrySubscribeChannel(int id, out Channel channel) + { + throw new NotImplementedException(); + } + + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_udpRpcActors.Clear(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + GetUdpRpcActor(remoteEndPoint).InputReceivedData(byteBlock); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + m_serializationSelector = config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + base.LoadConfig(config); + } + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private UdpRpcActor GetUdpRpcActor(EndPoint endPoint) + { + if (!m_udpRpcActors.TryGetValue(endPoint, out UdpRpcActor udpRpcActor)) + { + udpRpcActor = new UdpRpcActor(this, endPoint, Container.Resolve()) + { + Caller = new UdpCaller(this, endPoint), + RpcStore = m_rpcStore, + GetInvokeMethod = GetInvokeMethod, + SerializationSelector = m_serializationSelector + }; + m_udpRpcActors.TryAdd(endPoint, udpRpcActor); + } + udpRpcActor.Tick++; + return udpRpcActor; + } + + private UdpRpcActor GetUdpRpcActor() + { + if (RemoteIPHost == null) + { + throw new ArgumentNullException(nameof(RemoteIPHost)); + } + return GetUdpRpcActor(RemoteIPHost.EndPoint); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs.meta new file mode 100644 index 0000000..824723c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 174de2e976ea52f41a2f06b59caa090b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket.meta new file mode 100644 index 0000000..a275629 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29a69bef2a26bd042b44f96f98863abe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface.meta new file mode 100644 index 0000000..f0db35c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a3731d8e24c9024a85e5254d0f5b656 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs new file mode 100644 index 0000000..315e982 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IWSTouchRpcClient + /// + public interface IWSTouchRpcClient : IWSTouchRpcClientBase, IRpcParser + { + /// + /// 异步连接 + /// + /// 验证超时时间 + /// + Task ConnectAsync(int timeout = 5000); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs.meta new file mode 100644 index 0000000..7e157cd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e3d6892b770b6d4c85390cc615f9608 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs new file mode 100644 index 0000000..aa46a13 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc辅助类基类 + /// + public interface IWSTouchRpcClientBase: ITouchRpc, IPluginObject, ISenderBase + { + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs.meta new file mode 100644 index 0000000..6a1d9a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClientBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1441a77ba6302ba41bd32e1b8dab48b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs new file mode 100644 index 0000000..99f3c7d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs @@ -0,0 +1,731 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// WSTouchRpcClient + /// + public partial class WSTouchRpcClient : DisposableObject, IWSTouchRpcClient + { + private readonly ActionMap m_actionMap; + private readonly ArraySegment m_buffer; + private readonly RpcActor m_rpcActor; + private ClientWebSocket m_client; + private TouchSocketConfig m_config; + private IPHost m_remoteIPHost; + private RpcStore m_rpcStore; + + /// + /// 创建一个WSTouchRpcClient实例。 + /// + public WSTouchRpcClient() + { + m_buffer = new ArraySegment(new byte[1024 * 64]); + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnRouting = OnRpcActorRouting, + OnHandshaked = OnRpcActorHandshaked, + OnReceived = OnRpcActorReceived, + GetInvokeMethod = GetInvokeMethod, + OnClose = OnRpcServiceClose, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + Caller = this + }; + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public bool CanSend => m_client.State == WebSocketState.Open; + + /// + /// 客户端配置 + /// + public TouchSocketConfig Config => m_config; + + /// + public IContainer Container { get; private set; } + + /// + /// 断开连接 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor.IsHandshaked; + + /// + /// 最后活动时间 + /// + public DateTime LastActiveTime { get; private set; } + + /// + public ILog Logger => m_rpcActor.Logger; + + /// + public IPluginsManager PluginsManager { get; private set; } + + /// + public IPHost RemoteIPHost => m_remoteIPHost; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore { get => m_rpcStore; } + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get => m_rpcActor.TryCanInvoke; set => m_rpcActor.TryCanInvoke = value; } + + /// + public bool UsePlugin { get; private set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + /// 关闭 + /// + /// + public void Close(string msg) + { + if (m_client?.State != WebSocketState.Open) + { + return; + } + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + BreakOut($"调用{nameof(Close)}", true); + } + + /// + public async Task ConnectAsync(int timeout = 5000) + { + if (!RemoteIPHost.IsUri) + { + throw new Exception("RemoteIPHost必须为Uri格式。"); + } + if (m_client == null || m_client.State != WebSocketState.Open) + { + m_client.SafeDispose(); + m_client = new ClientWebSocket(); + await m_client.ConnectAsync(RemoteIPHost.Uri, default).ConfigureAwait(false); + + BeginReceive(); + } + + if (IsHandshaked) + { + return; + } + + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + } + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + /// 配置 + /// + /// + /// + public IWSTouchRpcClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return Setup(config); + } + + /// + /// 配置 + /// + /// + /// + public IWSTouchRpcClient Setup(TouchSocketConfig clientConfig) + { + m_config = clientConfig; + LoadConfig(m_config); + return this; + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + /// + protected override void Dispose(bool disposing) + { + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + m_remoteIPHost = config.GetValue(Sockets.TouchSocketConfigExtension.RemoteIPHostProperty); + Container = config.Container; + UsePlugin = config.IsUsePlugin; + PluginsManager = config.PluginsManager; + + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + + } + + /// + /// 已断开连接。 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(IDisconnectedPlguin.OnDisconnected), this, e)) + { + return; + } + Disconnected?.Invoke(this, e); + } + + private void BeginReceive() + { + Task.Factory.StartNew(async() => + { + try + { + ByteBlock byteBlock = null; + int bufferLength = this.Config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + while (true) + { + byteBlock ??= new ByteBlock(bufferLength); + var result = await m_client.ReceiveAsync(m_buffer, default); + if (result.Count == 0) + { + BreakOut("远程终端主动关闭", false); + return; + } + LastActiveTime = DateTime.Now; + byteBlock.Write(m_buffer.Array, 0, result.Count); + if (result.EndOfMessage) + { + try + { + m_rpcActor.InputReceivedData(byteBlock); + } + catch + { + } + finally + { + byteBlock.SafeDispose(); + byteBlock = default; + } + } + } + + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + },TaskCreationOptions.LongRunning); + } + + private void BreakOut(string msg, bool manual) + { + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + OnDisconnected(new DisconnectEventArgs(manual, msg)); + } + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + + #region FileTransfer + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + #endregion FileTransfer + + #region RPC + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + #endregion RPC + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private async void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + LastActiveTime = DateTime.Now; + for (int i = 0; i < transferBytes.Length; i++) + { + if (i == transferBytes.Length - 1) + { + await m_client.SendAsync(transferBytes[i], WebSocketMessageType.Binary, true, CancellationToken.None); + } + else + { + await m_client.SendAsync(transferBytes[i], WebSocketMessageType.Binary, false, CancellationToken.None); + } + } + } + + #endregion 内部委托绑定 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(VerifyOptionEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs.meta new file mode 100644 index 0000000..af406a0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d09bd2464a0a684f96f3dc0033a60c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config.meta new file mode 100644 index 0000000..748a790 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9b1ff1837ddf3b4181f27d369cf047f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs new file mode 100644 index 0000000..3a4f023 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs @@ -0,0 +1,284 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc配置扩展 + /// + public static class TouchRpcConfigExtensions + { + /// + /// 默认使用Id。 + /// + public static readonly DependencyProperty DefaultIdProperty = + DependencyProperty.Register("DefaultId", typeof(TouchRpcConfigExtensions), null); + + /// + /// TouchClient连接时的元数据, 所需类型 + /// + public static readonly DependencyProperty MetadataProperty = DependencyProperty.Register("Metadata", typeof(TouchRpcConfigExtensions), null); + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializationSelectorProperty = + DependencyProperty.Register("SerializationSelector", typeof(TouchRpcConfigExtensions), new DefaultSerializationSelector()); + + /// + /// 验证超时时间,默认为3000ms, 所需类型 + /// + public static readonly DependencyProperty VerifyTimeoutProperty = + DependencyProperty.Register("VerifyTimeout", typeof(TouchRpcConfigExtensions), 3000); + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型 + /// + public static readonly DependencyProperty VerifyTokenProperty = + DependencyProperty.Register("VerifyToken", typeof(TouchRpcConfigExtensions), "rrqm"); + + /// + /// 设置默认的使用Id。仅在TouchRpc组件适用。 + /// + /// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。 + /// + /// + /// + /// + /// + public static TouchSocketConfig SetDefaultId(this TouchSocketConfig config, string value) + { + config.SetValue(DefaultIdProperty, value); + return config; + } + + /// + /// 心跳频率,默认为间隔2000ms,3次。(设置为null时禁止心跳) + /// 仅适用于TouchRpcClient系类 + /// + /// + /// + /// + [Obsolete("该方法已被弃用。请使用插件UseTouchRpcHeartbeat替代。", true)] + public static TouchSocketConfig SetHeartbeatFrequency(this TouchSocketConfig config, object value) + { + throw new NotImplementedException(); + } + + /// + /// 设置TouchClient连接时的元数据 + /// 仅适用于TouchRpcClient系类 + /// + /// + /// + /// + public static TouchSocketConfig SetMetadata(this TouchSocketConfig config, Metadata value) + { + config.SetValue(MetadataProperty, value); + return config; + } + + /// + /// 设置序列化转换器 + /// + /// + /// + /// + public static TouchSocketConfig SetSerializationSelector(this TouchSocketConfig config, SerializationSelector value) + { + config.SetValue(SerializationSelectorProperty, value); + return config; + } + + /// + /// 验证超时时间,默认为3000ms. + /// 该配置仅有效 + /// + /// + /// + /// + public static TouchSocketConfig SetVerifyTimeout(this TouchSocketConfig config, int value) + { + config.SetValue(VerifyTimeoutProperty, value); + return config; + } + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm” + /// + /// + /// + /// + public static TouchSocketConfig SetVerifyToken(this TouchSocketConfig config, string value) + { + config.SetValue(VerifyTokenProperty, value); + return config; + } + + #region FileTransfer + + /// + /// 根目录 + /// 所需类型 + /// + public static readonly DependencyProperty RootPathProperty = DependencyProperty.Register("RootPath", typeof(TouchRpcConfigExtensions), string.Empty); + + /// + /// 设置根路径 + /// + /// + /// + /// + public static TouchSocketConfig SetRootPath(this TouchSocketConfig config, string value) + { + config.SetValue(RootPathProperty, value); + return config; + } + + #endregion FileTransfer + + #region 创建TcpTouchRpc + + /// + /// 构建TcpTouchRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithTcpTouchRpcClient(this TouchSocketConfig config) where TClient : ITcpTouchRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建TcpTouchRpc类客户端,并连接 + /// + /// + /// + public static TcpTouchRpcClient BuildWithTcpTouchRpcClient(this TouchSocketConfig config) + { + return BuildWithTcpTouchRpcClient(config); + } + + /// + /// 构建TcpTouchRpc类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithTcpTouchRpcService(this TouchSocketConfig config) where TService : ITcpTouchRpcService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建TcpTouchRpc类服务器,并启动。 + /// + /// + /// + public static TcpTouchRpcService BuildWithTcpTouchRpcService(this TouchSocketConfig config) + { + return BuildWithTcpTouchRpcService(config); + } + + #endregion 创建TcpTouchRpc + + #region 创建HttpTouchRpc + + /// + /// 构建HttpTouchRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithHttpTouchRpcClient(this TouchSocketConfig config) where TClient : IHttpTouchRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建HttpTouchRpc类客户端,并连接 + /// + /// + /// + public static HttpTouchRpcClient BuildWithHttpTouchRpcClient(this TouchSocketConfig config) + { + return BuildWithHttpTouchRpcClient(config); + } + + /// + /// 构建HttpTouchRpc类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithHttpTouchRpcService(this TouchSocketConfig config) where TService : IHttpTouchRpcService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建HttpTouchRpc类服务器,并启动。 + /// + /// + /// + public static HttpTouchRpcService BuildWithHttpTouchRpcService(this TouchSocketConfig config) + { + return BuildWithHttpTouchRpcService(config); + } + + #endregion 创建HttpTouchRpc + + #region 创建UdpTouchRpc + + /// + /// 构建UdpTouchRpc类 + /// + /// + /// + /// + public static TClient BuildWithUdpTouchRpc(this TouchSocketConfig config) where TClient : IUdpTouchRpc + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Start(); + return client; + } + + /// + /// 构建UdpTouchRpc类客户端 + /// + /// + /// + public static UdpTouchRpc BuildWithUdpTouchRpc(this TouchSocketConfig config) + { + return BuildWithUdpTouchRpc(config); + } + + #endregion 创建UdpTouchRpc + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs.meta new file mode 100644 index 0000000..11cb035 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af69fbf9dac984c46aeee1412e6682f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum.meta new file mode 100644 index 0000000..4254056 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b97b356196d1b74eb763be1401caebc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs new file mode 100644 index 0000000..6ac1de9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 路由类型 + /// + public readonly struct RouteType + { + private readonly string value; + + /// + /// 路由类型 + /// + /// + public RouteType(string value) + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException($"“{nameof(value)}”不能为 null 或空。", nameof(value)); + } + + this.value = value.ToLower().Trim(); + } + + /// + /// 判断RouteType是相等。 + /// + /// + /// + /// + public static bool operator ==(RouteType a, RouteType b) + { + return a.value == b.value; + } + + /// + /// 判断RouteType不相等。 + /// + /// + /// + /// + public static bool operator !=(RouteType a, RouteType b) + { + return a.value != b.value; + } + + /// + /// + /// + /// + /// + public override bool Equals(object obj) + { + if (obj is RouteType type) + { + return this == type; + } + return false; + } + + /// + /// + /// + /// + public override int GetHashCode() + { + return this.value.GetHashCode(); + } + + /// + /// + /// + /// + public override string ToString() => value; + + /// + /// 一个Ping探测路由包 + /// + public static readonly RouteType Ping = new RouteType("Ping"); + + /// + /// 创建通道路由包。 + /// + public static readonly RouteType CreateChannel = new RouteType("CreateChannel"); + + /// + /// Rpc调用的路由包 + /// + public static readonly RouteType Rpc = new RouteType("Rpc"); + + /// + /// 拉取文件的路由包 + /// + public static readonly RouteType PullFile = new RouteType("PullFile"); + + /// + /// 加载远程流数据 + /// + public static readonly RouteType LoadRemoteStream = new RouteType("LoadRemoteStream"); + + /// + /// 推送文件的路由包 + /// + public static readonly RouteType PushFile = new RouteType("PushFile"); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs.meta new file mode 100644 index 0000000..99cf63d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a2bd78ce3459f64da9d5e9583436442 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs new file mode 100644 index 0000000..68b7cd5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 传输标识 + /// + [Flags] + public enum TransferFlags : byte + { + /// + /// 无任何标识 + /// + None = 0, + + /// + /// 断点续传。 + /// 使用该标识时,会使用文件长度验证续传的有效性。如果需要,也可以附加验证。 + /// + BreakpointResume = 1, + + /// + /// MD5验证。该标识在文件传输完成时,也会再次验证文件长度。 + /// + MD5Verify = 2, + + /// + /// 当传输失败时,删除所有缓存文件。 + /// 注意:当启用断点续传时,该标识无效 + /// + DeleteWhenFail = 4 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs.meta new file mode 100644 index 0000000..457d888 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51456d5782697a948810e65886ef1f9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs new file mode 100644 index 0000000..e78e900 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 传输类型 + /// + [Flags] + public enum TransferType + { + /// + /// 推送 + /// + Push = 0, + + /// + /// 拉取 + /// + Pull = 1, + + /// + /// 分块推送 + /// + SectionPush = 2, + + /// + /// 分块拉取 + /// + SectionPull = 4, + + /// + /// 小文件推送 + /// + SmallPush = 8, + + /// + /// 小文件拉取 + /// + SmallPull = 16 + } + + /// + /// TransferTypeExtension + /// + public static class TransferTypeExtension + { + /// + /// 表示当前传输类型是否属于其中的一种。 + /// + /// + /// + public static bool IsPull(this TransferType transferType) + { + return transferType == TransferType.Pull || transferType == TransferType.SmallPull || transferType == TransferType.SectionPull; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs.meta new file mode 100644 index 0000000..235a60a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9dca5d45233a4f544a201dba1ec9e051 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs.meta new file mode 100644 index 0000000..ab89a3d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f4ced7ac75266d46a33a999499c9794 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs new file mode 100644 index 0000000..e014982 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 操作文件事件类 + /// + public class FileOperationEventArgs : MsgEventArgs + { + private string m_savePath; + private string m_resourcePath; + private readonly Metadata m_metadata; + + /// + /// FileOperationEventArgs + /// + /// + /// + /// + public FileOperationEventArgs(TransferType transferType, FileOperator fileOperator, RemoteFileInfo fileInfo) + { + FileOperator = fileOperator; + TransferType = transferType; + FileInfo = fileInfo; + } + + /// + /// FileOperationEventArgs + /// + /// + /// + /// + public FileOperationEventArgs(TransferType transferType, Metadata metadata, RemoteFileInfo fileInfo) + { + FileOperator = default; + TransferType = transferType; + FileInfo = fileInfo; + m_metadata = metadata; + } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath + { + get => FileOperator == null ? m_savePath : FileOperator.SavePath; + set + { + if (FileOperator == null) + { + m_savePath = value; + } + else + { + FileOperator.SavePath = value; + } + } + } + + /// + /// 请求文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath + { + get => FileOperator == null ? m_resourcePath : FileOperator.ResourcePath; + set + { + if (FileOperator == null) + { + m_resourcePath = value; + } + else + { + FileOperator.ResourcePath = value; + } + } + } + + /// + /// 元数据 + /// + public Metadata Metadata => FileOperator == null ? m_metadata : FileOperator.Metadata; + + /// + /// 文件操作器 + /// + public FileOperator FileOperator { get; private set; } + + /// + /// 文件信息 + /// + public RemoteFileInfo FileInfo { get; private set; } + + /// + /// 传输标识 + /// + public TransferFlags Flags { get => FileOperator == null ? TransferFlags.None : FileOperator.Flags; } + + /// + /// 传输类型 + /// + public TransferType TransferType { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs.meta new file mode 100644 index 0000000..89e98c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7303c12b054f8d44a611a8c909bd65e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs new file mode 100644 index 0000000..25d6960 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件传输状态 + /// + public class FileTransferStatusEventArgs : FileOperationEventArgs + { + /// + /// FileTransferStatusEventArgs + /// + /// + /// + /// + /// + public FileTransferStatusEventArgs(TransferType transferType, Metadata metadata, RemoteFileInfo fileInfo, Result result) + : base(transferType, metadata, fileInfo) + { + Result = result; + } + + /// + /// FileTransferStatusEventArgs + /// + /// + /// + /// + /// + public FileTransferStatusEventArgs(TransferType transferType, Result result, RemoteFileInfo fileInfo, FileOperator fileOperator) + : base(transferType, fileOperator, fileInfo) + { + Result = result; + } + + /// + /// FileTransferStatusEventArgs + /// + /// + /// + public FileTransferStatusEventArgs(Result result, FileOperationEventArgs args) + : base(args.TransferType, args.FileOperator, args.FileInfo) + { + Result = result; + } + + /// + /// 结果 + /// + public Result Result { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs.meta new file mode 100644 index 0000000..53f8440 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 313f2065d9c1c7048bd80a76c11f4a44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs new file mode 100644 index 0000000..a43f12d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http验证 + /// + public class HttpVerifyOptionEventArgs : HttpContextEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public HttpVerifyOptionEventArgs(HttpContext context, string token) : base(context) + { + Token = token; + } + + /// + /// 验证令箭 + /// + public string Token { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs.meta new file mode 100644 index 0000000..2f22c43 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae64887c02e5b4444af1dc49bd97c9bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs new file mode 100644 index 0000000..1ac24a4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// PackageRouterEventArgs + /// + public class PackageRouterEventArgs : MsgEventArgs + { + /// + /// PackageRouterEventArgs + /// + /// + /// + public PackageRouterEventArgs(RouteType routerType, RouterPackage package) + { + RouterType = routerType; + Package = package; + } + + /// + /// 路由类型 + /// + public RouteType RouterType { get; private set; } + + /// + /// 路由数据包。一般为不完全数据,仅包含基本的路由信息。 + /// + public RouterPackage Package { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs.meta new file mode 100644 index 0000000..ca57703 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95268093c582e2a43a320033a35a5768 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs new file mode 100644 index 0000000..ab93b93 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 协议数据事件 + /// + public class ProtocolDataEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public ProtocolDataEventArgs(short protocol, ByteBlock byteBlock) + { + Protocol = protocol; + ByteBlock = byteBlock; + } + + /// + /// 数据流,实际解析时应当偏移两个字节 + /// + public ByteBlock ByteBlock { get; } + + /// + /// 协议 + /// + public short Protocol { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs.meta new file mode 100644 index 0000000..7174158 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 477102bce2dc2584ba143a970cda2888 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs new file mode 100644 index 0000000..22c9e93 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流事件参数 + /// + public class StreamEventArgs : MsgEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public StreamEventArgs(Metadata metadata, StreamInfo streamInfo) + { + Metadata = metadata; + StreamInfo = streamInfo; + } + + /// + /// 用于接收流的容器 + /// + public Stream Bucket { get; set; } + + /// + /// 用于可传输的元数据 + /// + public Metadata Metadata { get; private set; } + + /// + /// 流信息 + /// + public StreamInfo StreamInfo { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs.meta new file mode 100644 index 0000000..9e2fdf3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20f49faead703dd4a83d845f448d28c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs new file mode 100644 index 0000000..0e395f0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 接收流数据 + /// + public class StreamOperationEventArgs : StreamEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public StreamOperationEventArgs(StreamOperator streamOperator, Metadata metadata, StreamInfo streamInfo) : base(metadata, streamInfo) + { + StreamOperator = streamOperator ?? throw new ArgumentNullException(nameof(streamOperator)); + IsPermitOperation = true; + } + + /// + /// 流操作 + /// + public StreamOperator StreamOperator { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs.meta new file mode 100644 index 0000000..c3c4b94 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d06398054b091b46a6076d572cb5596 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs new file mode 100644 index 0000000..1894073 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有返回状态的流 + /// + public class StreamStatusEventArgs : StreamEventArgs + { + private Result result; + + /// + /// 结果 + /// + public Result Result => result; + + /// + /// 构造函数 + /// + /// + /// + /// + public StreamStatusEventArgs(Result result, Metadata metadata, StreamInfo streamInfo) : base(metadata, streamInfo) + { + this.result = result; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs.meta new file mode 100644 index 0000000..13029c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd082737ad92eff48a0d1aca2f11c5a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs new file mode 100644 index 0000000..9e7b1e5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 连接验证 + /// + public class VerifyOptionEventArgs : MsgEventArgs + { + /// + /// 令箭 + /// + public string Token { get; private set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; private set; } + + /// + /// 构造函数 + /// + /// + /// + public VerifyOptionEventArgs(string token, Metadata metadata) + { + Token = token; + Metadata = metadata; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs.meta new file mode 100644 index 0000000..babbe20 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ef3395284cde3b498a558b688663d97 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions.meta new file mode 100644 index 0000000..78d0bf1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b768827c793541044949c9eff75c3030 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs new file mode 100644 index 0000000..06be32b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 协议异常 + /// + [Serializable] + public class ProtocolException : Exception + { + /// + /// 构造函数 + /// + public ProtocolException() + { } + + /// + /// 构造函数 + /// + /// + public ProtocolException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public ProtocolException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected ProtocolException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs.meta new file mode 100644 index 0000000..29ec272 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df128d079170e2d43ac53f1c08adaf93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs new file mode 100644 index 0000000..4893439 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Token验证异常 + /// + [Serializable] + public class TokenVerifyException : Exception + { + /// + /// 构造函数 + /// + public TokenVerifyException() + { } + + /// + /// 构造函数 + /// + /// + public TokenVerifyException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public TokenVerifyException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected TokenVerifyException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs.meta new file mode 100644 index 0000000..510c658 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 345691547704bbe4f88585643229f350 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs new file mode 100644 index 0000000..7eb8584 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc添加方法键异常 + /// + public class RpcKeyException : Exception + { + /// + ///构造函数 + /// + public RpcKeyException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcKeyException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcKeyException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcKeyException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// Rpc无注册异常 + /// + public class RpcNoRegisterException : Exception + { + /// + ///构造函数 + /// + public RpcNoRegisterException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcNoRegisterException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcNoRegisterException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcNoRegisterException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// 序列化异常类 + /// + public class RpcSerializationException : Exception + { + /// + ///构造函数 + /// + public RpcSerializationException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcSerializationException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcSerializationException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcSerializationException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs.meta new file mode 100644 index 0000000..b741bdf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4cc6b259f242a0e44b94e365f337dcdd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions.meta new file mode 100644 index 0000000..e5e834e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61b192548061b6f47864a74a9f434620 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs new file mode 100644 index 0000000..98ec509 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs @@ -0,0 +1,244 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorExtensions + /// + public static partial class RpcActorExtensions + { + #region 尝试发送 + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, byte[] buffer, int offset, int length) where TRpcActor : IRpcActorSender + { + try + { + rpcActor.Send(protocol, buffer, offset, length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActorSender + { + try + { + rpcActor.Send(protocol, buffer, 0, buffer.Length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActorSender + { + try + { + rpcActor.Send(protocol); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, ByteBlock byteBlock) where TRpcActor : IRpcActorSender + { + try + { + rpcActor.Send(protocol, byteBlock); + return true; + } + catch + { + return false; + } + } + + #endregion 尝试发送 + + #region 尝试异步发送 + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer, int offset, int length) where TRpcActor : IRpcActorSender + { + try + { + await rpcActor.SendAsync(protocol, buffer, offset, length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActorSender + { + try + { + await rpcActor.SendAsync(protocol, buffer, 0, buffer.Length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActorSender + { + try + { + await rpcActor.SendAsync(protocol); + return true; + } + catch + { + return false; + } + } + + #endregion 尝试异步发送 + + #region 发送 + + /// + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActorSender + { + rpcActor.Send(protocol, buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActorSender + { + rpcActor.Send(protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + /// + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol, ByteBlock byteBlock) where TRpcActor : IRpcActorSender + { + rpcActor.Send(protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static Task SendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActorSender + { + return rpcActor.SendAsync(protocol, buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + /// + /// + /// + public static Task SendAsync(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActorSender + { + return rpcActor.SendAsync(protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs.meta new file mode 100644 index 0000000..41e7e27 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 248b2a827c4ac80488f0bc2562b8f7b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs new file mode 100644 index 0000000..f86c3aa --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcContainerExtension + /// + public static class TouchRpcContainerExtension + { + /// + /// 设置文件资源控制器。 + /// + /// + /// + public static IContainer SetFileResourceController(this IContainer container, IFileResourceController value) + { + return container.RegisterSingleton(value); + } + + /// + /// 设置文件资源控制器。 + /// + /// + /// + public static IContainer SetFileResourceController(this IContainer container) where T : class, IFileResourceController + { + return container.RegisterSingleton(); + } + + /// + /// 默认的全局资源控制器。 + /// + public static readonly FileResourceController FileController = new FileResourceController(); + + /// + /// 获取文件资源控制器。如果没有注册的话,会新建一个 + /// + /// + public static IFileResourceController GetFileResourceController(this IContainer container) + { + if (container.IsRegistered(typeof(IFileResourceController))) + { + return container.Resolve(); + } + return FileController; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs.meta new file mode 100644 index 0000000..5d7b87a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 945ee49a43c7d714a9d9e41f3e48cf90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs new file mode 100644 index 0000000..22bfb80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs @@ -0,0 +1,334 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RPC辅助扩展 + /// + public static partial class TouchRpcExtensions + { + /// + /// 创建一个直接向目标地址请求的Rpc客户端。 + /// + /// + /// + public static IRpcClient CreateIDRpcClient(this TRpcActor client, string targetId) where TRpcActor : IRpcActor + { + return new IDRpcActor(targetId, client); + } + + #region 批量传输(弃用) + + /// + /// 批量拉取文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PullFiles(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PullFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.Run(); + } + + /// + /// 异步批量拉取文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PullFilesAsync(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PullFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.RunAsync(); + } + + /// + /// 批量推送文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PushFiles(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PushFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.Run(); + } + + /// + /// 异步批量推送文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PushFilesAsync(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PushFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.RunAsync(); + } + + #endregion 批量传输(弃用) + + /// + /// 转化Protocol协议标识为TouchRpc + /// + /// + public static void SwitchProtocolToTouchRpc(this ITcpClientBase client) + { + client.SetDataHandlingAdapter(new FixedHeaderPackageAdapter()); + client.Protocol = TouchRpcUtility.TouchRpcProtocol; + } + + /// + /// 转为ResultCode + /// + /// + /// + public static ResultCode ToResultCode(this ChannelStatus channelStatus) + { + switch (channelStatus) + { + case ChannelStatus.Default: + return ResultCode.Default; + + case ChannelStatus.Overtime: + return ResultCode.Overtime; + + case ChannelStatus.Cancel: + return ResultCode.Canceled; + + case ChannelStatus.Completed: + return ResultCode.Success; + + case ChannelStatus.Moving: + case ChannelStatus.Disposed: + default: + return ResultCode.Error; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs.meta new file mode 100644 index 0000000..033b22a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 264166eb7529dbc4aa095254007a01d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs new file mode 100644 index 0000000..c2f4631 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Core +{ + /// + /// TouchRpcPluginsManagerExtension + /// + public static partial class TouchRpcPluginsManagerExtension + { + /// + /// 使用Redis插件。仅:TouchRpc组成员会生效。 + /// + /// + /// + public static RedisPlugin UseRedis(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + + /// + /// TouchRpc心跳。仅客户端适用。 + /// + /// 默认心跳每3秒进行一次。最大失败3次即判定为断开连接。 + /// + /// + /// + /// + /// + public static TouchRpcHeartbeatPlugin UseTouchRpcHeartbeat(this IPluginsManager pluginsManager) where TClient : class, ITcpClientBase, IDependencyTouchRpc + { + return pluginsManager.Add>(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..8103aeb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b03ac7424b2de843a20ba49413cbb6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs new file mode 100644 index 0000000..09d0972 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcServiceExtension + /// + public static class TouchRpcServiceExtension + { + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol, byte[] buffer) + { + service.Send(targetId, protocol, buffer, 0, buffer.Length); + } + + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol) + { + service.Send(targetId, protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol, ByteBlock byteBlock) + { + service.Send(targetId, protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + public static Task SendAsync(this ITouchRpcService service, string targetId, short protocol, byte[] buffer) + { + return service.SendAsync(targetId, protocol, buffer, 0, buffer.Length); + } + + /// + public static Task SendAsync(this ITouchRpcService service, string targetId, short protocol) + { + return service.SendAsync(targetId, protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs.meta new file mode 100644 index 0000000..63e2bd6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2cdb0e304bfaa4b4a9b71dba702dfccf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File.meta new file mode 100644 index 0000000..52000aa --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f0a538629c353a46aa648b4dd05c615 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs new file mode 100644 index 0000000..0ae0eee --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件传输操作器 + /// + public class FileOperator : RemoteFileOperator + { + /// + /// 传输标识 + /// + public TransferFlags Flags { get; set; } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath { get; set; } + + /// + /// 资源文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs.meta new file mode 100644 index 0000000..96461aa --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb3bc5799ac07de48a8194a53768ac53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs new file mode 100644 index 0000000..e9ff040 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件资源控制器。 + /// + public class FileResourceController : IFileResourceController + { + /// + public virtual void GetFileInfo(string path, bool md5, ref T fileInfo) where T : RemoteFileInfo + { + FileInfo info = new FileInfo(path); + fileInfo.FullName = info.FullName; + fileInfo.Name = info.Name; + fileInfo.Attributes = info.Attributes; + fileInfo.CreationTime = info.CreationTime; + fileInfo.Length = info.Length; + fileInfo.LastAccessTime = info.LastAccessTime; + fileInfo.LastWriteTime = info.LastWriteTime; + + if (md5) + { + using FileStream fileStream = File.OpenRead(path); + fileInfo.MD5 = FileUtility.GetStreamMD5(fileStream); + } + } + + /// + public virtual string GetFullPath(string root, string path) + { + if (path.IsNullOrEmpty()) + { + return string.Empty; + } + if (Path.IsPathRooted(path)) + { + return path; + } + else + { + return Path.GetFullPath(Path.Combine(root, path)); + } + } + + /// + public virtual bool TryReadTempInfo(string path, TransferFlags flags, ref TouchRpcFileInfo info) + { + if (flags == TransferFlags.None) + { + return false; + } + string filePath = path + ".rrqm"; + string tempPath = path + ".temp"; + if (File.Exists(filePath) && File.Exists(tempPath)) + { + try + { + FileInfo fileInfo = new FileInfo(filePath); + TouchRpcFileInfo tempInfo = SerializeConvert.JsonDeserializeFromString(File.ReadAllText(tempPath)); + if (flags.HasFlag(TransferFlags.BreakpointResume)) + { + if (tempInfo.Length != info.Length) + { + return false; + } + if (flags.HasFlag(TransferFlags.MD5Verify)) + { + if ((tempInfo.MD5 == info.MD5 && info.MD5.HasValue())) + { + info.Position = tempInfo.Position; + return true; + } + } + else + { + info.Position = tempInfo.Position; + return true; + } + } + else + { + return false; + } + } + catch + { + return false; + } + } + return false; + } + + /// + public virtual int ReadAllBytes(FileInfo fileInfo, byte[] buffer) + { + using (FileStorageReader reader = FilePool.GetReader(fileInfo)) + { + return reader.Read(buffer, 0, buffer.Length); + } + } + + /// + public virtual void WriteAllBytes(FileInfo fileInfo, byte[] buffer, int offset, int length) + { + FileUtility.Delete(fileInfo.FullName); + using (var writer = FilePool.GetWriter(fileInfo)) + { + writer.Write(buffer, offset, length); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs.meta new file mode 100644 index 0000000..0b095c3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a10932702fbb65a4c97f4c3726225b01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs new file mode 100644 index 0000000..7daf4b9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.IO; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件资源控制器。 + /// + public interface IFileResourceController + { + /// + /// 获取文件信息 + /// + /// + /// + /// + /// + void GetFileInfo(string path, bool md5, ref T fileInfo) where T : RemoteFileInfo; + + /// + /// 获取全路径 + /// + /// + /// + /// + string GetFullPath(string root, string path); + + /// + /// 读取缓存文件信息 + /// + /// + /// + /// + /// + bool TryReadTempInfo(string path, TransferFlags flags, ref TouchRpcFileInfo info); + + /// + /// 读取文件的所有数据 + /// + /// + /// + /// + int ReadAllBytes(FileInfo fileInfo, byte[] buffer); + + /// + /// 写入数据到文件 + /// + /// + /// + /// + /// + void WriteAllBytes(FileInfo fileInfo, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs.meta new file mode 100644 index 0000000..d304b57 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 343366d7abd49d34b9907bc1c32ae7e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs new file mode 100644 index 0000000..8dd017f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// PullSmallFileResult + /// + public class PullSmallFileResult : ResultBase + { + /// + /// 初始化PullSmallFileResult + /// + /// + /// + public PullSmallFileResult(ResultCode resultCode, string message) : base(resultCode, message) + { + } + + /// + /// 初始化PullSmallFileResult + /// + /// + public PullSmallFileResult(byte[] bytes) : base(ResultCode.Success) + { + Value = bytes; + } + + /// + /// 初始化PullSmallFileResult + /// + /// + public PullSmallFileResult(ResultCode resultCode) : base(resultCode) + { + } + + /// + /// 实际的文件数据 + /// + public byte[] Value { get; private set; } + + /// + /// 将拉取的数据保存为文件。 + /// + /// + /// + /// + public Result Save(string path, bool overwrite = true) + { + try + { + if (overwrite) + { + FileUtility.Delete(path); + } + using (FileStorageWriter writer = FilePool.GetWriter(path)) + { + writer.Write(Value); + return Result.Success; + } + } + catch (Exception ex) + { + return new Result(ex); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs.meta new file mode 100644 index 0000000..f88bdfd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0edb60ff7c27d64db621969dd32d6c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs new file mode 100644 index 0000000..89b9c5e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.IO; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RemoteFileInfo + /// + public class RemoteFileInfo : RemoteFileSystemInfo + { + /// + /// 初始化一个RemoteFileInfo + /// + public RemoteFileInfo() + { + } + + /// + /// 从FileInfo初始化一个RemoteFileInfo + /// + /// + public RemoteFileInfo(FileInfo fileInfo) + { + FullName = fileInfo.FullName; + Name = fileInfo.Name; + Length = fileInfo.Length; + Attributes = fileInfo.Attributes; + CreationTime = fileInfo.CreationTime; + LastWriteTime = fileInfo.LastWriteTime; + LastAccessTime = fileInfo.LastAccessTime; + } + + /// + /// 文件MD5 + /// + public string MD5 { get; set; } + + /// + /// 文件大小 + /// + public long Length { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(MD5); + byteBlock.Write(Length); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + MD5 = byteBlock.ReadString(); + Length = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs.meta new file mode 100644 index 0000000..da56f88 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ef9472176922b746bc9b4622184fcaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs new file mode 100644 index 0000000..778823e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 远程文件控制器。 + /// + public class RemoteFileOperator : StreamOperator + { + internal void SetFileCompletedLength(long completedLength) + { + this.completedLength = completedLength; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs.meta new file mode 100644 index 0000000..2880621 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9e88fb0f248c004bb867a8881d9e075 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs new file mode 100644 index 0000000..ea913be --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 远程文件系统信息 + /// + public abstract class RemoteFileSystemInfo : PackageBase + { + /// + /// 目录或文件的名称。 + /// + public string Name { get; set; } + + /// + /// 目录或文件的完整目录。 + /// + public string FullName { get; set; } + + /// + /// 上次写入当前文件或目录的时间 + /// + public DateTime LastWriteTime { get; set; } + + /// + /// 上次访问当前文件或目录的时间 + /// + public DateTime LastAccessTime { get; set; } + + /// + /// 当前文件或目录的创建时间 + /// + public DateTime CreationTime { get; set; } + + /// + /// 当前文件或目录的特性 + /// + public FileAttributes Attributes { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + byteBlock.Write(LastWriteTime); + byteBlock.Write(LastAccessTime); + byteBlock.Write(CreationTime); + byteBlock.Write((int)Attributes); + byteBlock.Write(FullName); + byteBlock.Write(Name); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + LastWriteTime = byteBlock.ReadDateTime(); + LastAccessTime = byteBlock.ReadDateTime(); + CreationTime = byteBlock.ReadDateTime(); + Attributes = (FileAttributes)byteBlock.ReadInt32(); + FullName = byteBlock.ReadString(); + Name = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs.meta new file mode 100644 index 0000000..6939e01 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 782b8a3460a7b114f87857c5f6d3b178 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs new file mode 100644 index 0000000..2610349 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcFileInfo + /// + public class TouchRpcFileInfo : RemoteFileInfo + { + /// + /// 流位置 + /// + public long Position { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(Position); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + Position = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs.meta new file mode 100644 index 0000000..becef4f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5899375654909f642b56a385ba772ff3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs new file mode 100644 index 0000000..9e9c739 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件流 + /// + internal class TouchRpcFileStream : DisposableObject + { + private static int m_saveInterval = 1000; + + private TouchRpcFileInfo m_fileInfo; + + private FileStorageWriter m_fileWriter; + private TimeSpan m_lastTime; + + private string m_path; + + private bool m_resume; + + /// + /// 进度保存时间,默认1000毫秒。 + /// + public static int SaveInterval + { + get => m_saveInterval; + set + { + if (value < 0) + { + value = 0; + } + m_saveInterval = value; + } + } + + public FileStorageWriter FileWriter => m_fileWriter; + + public static TouchRpcFileStream Create(string path, ref TouchRpcFileInfo fileInfo, bool resume) + { + TouchRpcFileStream stream = new TouchRpcFileStream(); + stream.m_fileWriter = FilePool.GetWriter(path + ".rrqm"); + stream.m_fileWriter.Position = fileInfo.Position; + stream.m_fileInfo = fileInfo; + stream.m_path = path; + stream.m_resume = resume; + return stream; + } + + public void FinishStream() + { + if (m_fileWriter.Position != m_fileInfo.Length) + { + throw new Exception("已完成传输,但是文件长度不对。"); + } + if (File.Exists(m_path)) + { + File.Delete(m_path); + } + m_fileWriter.SafeDispose(); + + string rrqmPath = m_path + ".rrqm"; + string tempPath = m_path + ".temp"; + + if (!SpinWait.SpinUntil(() => + { + File.Move(rrqmPath, m_path); + if (File.Exists(tempPath)) + { + File.Delete(tempPath); + } + if (File.Exists(m_path)) + { + return true; + } + return false; + }, 5000)) + { + throw new IOException("已完成传输,但是在保存路径并未检测到文件存在。"); + } + } + + public void Write(byte[] buffer, int offset, int length) + { + m_fileWriter.Write(buffer, offset, length); + SaveProgress(); + } + + protected override void Dispose(bool disposing) + { + m_fileWriter.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 保存进度 + /// + private void SaveProgress() + { + if (m_resume) + { + if (DateTime.Now.TimeOfDay - m_lastTime > TimeSpan.FromMilliseconds(m_saveInterval)) + { + try + { + File.WriteAllText(m_path + ".temp", m_fileInfo.ToJson()); + m_lastTime = DateTime.Now.TimeOfDay; + } + catch + { + } + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs.meta new file mode 100644 index 0000000..c5ab313 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7fda6263ffdf44549828533a6d3b9980 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs new file mode 100644 index 0000000..3cf6c34 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件信息 + /// + internal class WaitFileInfoPackage : WaitRouterPackage + { + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 文件信息 + /// + public TouchRpcFileInfo FileInfo { get; set; } + + /// + /// 传输标识 + /// + public TransferFlags Flags { get; set; } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath { get; set; } + + /// + /// 请求文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath { get; set; } + + /// + /// 事件Code + /// + public int EventHashCode { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.WritePackage(Metadata); + byteBlock.WritePackage(FileInfo); + byteBlock.Write((byte)Flags); + byteBlock.Write(SavePath); + byteBlock.Write(ResourcePath); + byteBlock.Write(EventHashCode); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.Metadata = byteBlock.ReadPackage(); + this.FileInfo = byteBlock.ReadPackage(); + this.Flags = (TransferFlags)byteBlock.ReadByte(); + this.SavePath = byteBlock.ReadString(); + this.ResourcePath = byteBlock.ReadString(); + this.EventHashCode = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs.meta new file mode 100644 index 0000000..ff5d9c1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87b797e80ce08394cb683330481e5ea8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs new file mode 100644 index 0000000..3095e59 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitPushFileAckPackage : WaitRouterPackage + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs.meta new file mode 100644 index 0000000..d927542 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3c09ada94db0874dbad3c7eda5f0dbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs new file mode 100644 index 0000000..bef738a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitSmallFilePackage : WaitRouterPackage + { + public byte[] Data { get; set; } + public RemoteFileInfo FileInfo { get; set; } + public int Len { get; set; } + public Metadata Metadata { get; set; } + public string Path { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Path); + byteBlock.WritePackage(Metadata); + byteBlock.WritePackage(FileInfo); + byteBlock.WriteBytesPackage(Data, 0, Len); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + Path = byteBlock.ReadString(); + Metadata = byteBlock.ReadPackage(); + FileInfo = byteBlock.ReadPackage(); + Data = byteBlock.ReadBytesPackage(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs.meta new file mode 100644 index 0000000..80132f5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c739f445ae7c9b944a06146f99fe6e0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs new file mode 100644 index 0000000..8cd7fcb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 等待传输 + /// + internal class WaitTransferPackage : WaitRouterPackage + { + /// + /// 通道标识 + /// + public int ChannelID { get; set; } + + /// + /// 路径 + /// + public string Path { get; set; } + + /// + /// 流位置 + /// + public long Position { get; set; } + + /// + /// 事件Code + /// + public int EventHashCode { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(ChannelID); + byteBlock.Write(Path); + byteBlock.Write(Position); + byteBlock.Write(EventHashCode); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.ChannelID = byteBlock.ReadInt32(); + this.Path = byteBlock.ReadString(); + this.Position = byteBlock.ReadInt64(); + this.EventHashCode = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs.meta new file mode 100644 index 0000000..cf801c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0b4d8128da1c8043a19c3a223e76a6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue.meta new file mode 100644 index 0000000..508a526 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9e03c96aad098e49bb2c253db7363ed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs new file mode 100644 index 0000000..dcb3775 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 投递事件 + /// + public class DeliverEventArgs : EventArgs + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs.meta new file mode 100644 index 0000000..5816d85 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a2c2490c6050b54b83a8913061afba5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs new file mode 100644 index 0000000..6f98c33 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueueClient + /// + public abstract class MessageQueueClient + { + /// + /// 序列化转换器。 + /// + public BytesConverter Converter { get; set; } + + ///// + ///// 队列 + ///// + ///// + ///// + ///// + ///// + //public abstract void Publish(string queue, byte[] buffer,int offset,int length); + + //public abstract void Subscribe(string queue,Action<> data); + } + + internal class InternalMessageQueueClient : MessageQueueClient + { + private RpcActor m_rpcActor; + + public InternalMessageQueueClient(RpcActor rpcActor, BytesConverter converter) + { + m_rpcActor = rpcActor; + Converter = converter; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs.meta new file mode 100644 index 0000000..eb834cc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52771e385324f5a4eba837dd24ba9551 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs new file mode 100644 index 0000000..66f9297 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueueClientExtensions + /// + public static class MessageQueueClientExtensions + { + /// + /// 获取或设置MessageQueueClient的注入键。 + /// + public static readonly DependencyProperty MessageQueueClientProperty = + DependencyProperty.Register("MessageQueueClient", typeof(MessageQueueClientExtensions), null); + + /// + /// 获取MessageQueueClient + /// + /// + /// + /// + /// + public static MessageQueueClient GetMessageQueueClient(this TClient client) where TClient : IDependencyTouchRpc, IDependencyObject + { + return client.GetValue(MessageQueueClientProperty); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs.meta new file mode 100644 index 0000000..706ec34 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac4cca4d05ed980418b5ae540f239adb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs new file mode 100644 index 0000000..5ea3ecc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueuePlugin + /// + public class MessageQueuePlugin : TouchRpcPluginBase + { + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + public BytesConverter Converter { get; private set; } = new BytesConverter(); + + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + /// + public void SetConverter(BytesConverter converter) + { + Converter = converter; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(IDependencyTouchRpc client, VerifyOptionEventArgs e) + { + client.SetValue(MessageQueueClientExtensions.MessageQueueClientProperty, new InternalMessageQueueClient(client.RpcActor, Converter)); + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(IDependencyTouchRpc client, ProtocolDataEventArgs e) + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs.meta new file mode 100644 index 0000000..3818412 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ce1bdc86f38798449e5a70dbfe72133 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins.meta new file mode 100644 index 0000000..b320376 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d07da036e58f2b845932cf47a835ed68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs new file mode 100644 index 0000000..97c8549 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcPlugin + /// + public partial interface ITouchRpcPlugin : IPlugin + { + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + [AsyncRaiser] + void OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e); + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + Task OnFileTransferedAsync(ITouchRpc client, FileTransferStatusEventArgs e); + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + [AsyncRaiser] + void OnFileTransfering(ITouchRpc client, FileOperationEventArgs e); + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + /// + Task OnFileTransferingAsync(ITouchRpc client, FileOperationEventArgs e); + + /// + /// 在完成握手连接时。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 当需要转发路由包时 + /// + /// + /// + [AsyncRaiser] + void OnRouting(ITouchRpc client, PackageRouterEventArgs e); + + /// + /// 当需要转发路由包时 + /// + /// + /// + Task OnRoutingAsync(ITouchRpc client, PackageRouterEventArgs e); + + /// + /// 在完成握手连接时。 + /// + /// + /// + /// + Task OnHandshakedAsync(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 在验证Token时 + /// + /// + /// + /// + Task OnHandshakingAsync(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 收到协议数据 + /// + /// + /// + [AsyncRaiser] + void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e); + + /// + /// 收到协议数据 + /// + /// + /// + /// + Task OnReceivedProtocolDataAsync(ITouchRpc client, ProtocolDataEventArgs e); + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// 当流数据传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + [AsyncRaiser] + void OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e); + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// 当流数据传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + Task OnStreamTransferedAsync(ITouchRpc client, StreamStatusEventArgs e); + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + [AsyncRaiser] + void OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e); + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + /// + Task OnStreamTransferingAsync(ITouchRpc client, StreamOperationEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs.meta new file mode 100644 index 0000000..06dacf4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c3c72210502dac4aa62253464d9b210 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs new file mode 100644 index 0000000..d1e1caf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有委托能力的插件 + /// + public sealed partial class TouchRpcActionPlugin : TouchRpcPluginBase where TClient : ITouchRpc + { + private Action m_fileTransfered; + private Action m_fileTransfering; + private Action m_handshaked; + private Action m_handshaking; + private Action m_receivedProtocolData; + private Action m_streamTransfered; + private Action m_streamTransfering; + + /// + /// SetFileTransfered + /// + /// + /// + public TouchRpcActionPlugin SetFileTransfered(Action action) + { + m_fileTransfered = action; + return this; + } + + /// + /// SetFileTransfering + /// + /// + /// + public TouchRpcActionPlugin SetFileTransfering(Action action) + { + m_fileTransfering = action; + return this; + } + + /// + /// SetHandshaked + /// + /// + /// + public TouchRpcActionPlugin SetHandshaked(Action action) + { + m_handshaked = action; + return this; + } + + /// + /// SetHandshaking + /// + /// + /// + public TouchRpcActionPlugin SetHandshaking(Action action) + { + m_handshaking = action; + return this; + } + + /// + /// SetReceivedProtocolData + /// + /// + /// + public TouchRpcActionPlugin SetReceivedProtocolData(Action action) + { + m_receivedProtocolData = action; + return this; + } + + /// + /// SetStreamTransfered + /// + /// + /// + public TouchRpcActionPlugin SetStreamTransfered(Action action) + { + m_streamTransfered = action; + return this; + } + + /// + /// SetStreamTransfering + /// + /// + /// + public TouchRpcActionPlugin SetStreamTransfering(Action action) + { + m_streamTransfering = action; + return this; + } + + #region 重写 + + /// + /// + /// + /// + /// + protected override void OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e) + { + m_fileTransfered?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnFileTransfering(ITouchRpc client, FileOperationEventArgs e) + { + m_fileTransfering?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e) + { + m_handshaked?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + m_handshaking?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + m_receivedProtocolData?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e) + { + m_streamTransfered?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e) + { + m_streamTransfering?.Invoke((TClient)client, e); + } + + #endregion 重写 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs.meta new file mode 100644 index 0000000..7d4f7a7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32352777cbda79f4da7ad13ddfc0da28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs new file mode 100644 index 0000000..83e849f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcHeartbeatPlugin + /// + [SingletonPlugin] + public class TouchRpcHeartbeatPlugin : TouchRpcPluginBase where TClient : IDependencyObject, ITcpClientBase, IDependencyTouchRpc + { + private TClient m_client; + + private Thread m_thread; + + /// + /// 连接失败次数。当成功连接时,会重置为0。 + /// + public int FailedCount { get; private set; } + + /// + /// 心跳间隔。默认3秒。 + /// + public TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(3); + + /// + /// 最大失败次数,默认3。 + /// + public int MaxFailCount { get; set; } = 3; + + /// + /// 心跳间隔。默认3秒。 + /// + /// + /// + public TouchRpcHeartbeatPlugin SetInterval(TimeSpan value) + { + if (value == TimeSpan.Zero || value == TimeSpan.MaxValue || value == TimeSpan.MinValue) + { + throw new InvalidTimeZoneException("设置的时间必须为有效值。"); + } + Interval = value; + return this; + } + + /// + /// 最大失败次数,默认3。 + /// + /// + /// + public TouchRpcHeartbeatPlugin SetMaxFailCount(int value) + { + MaxFailCount = value; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + m_client = client; + if (m_thread == null) + { + m_thread = new Thread(ThreadHeartbeat) + { + IsBackground = true, + Name = $"{client}HeartbeatThread" + }; + m_thread.Start(); + } + base.OnHandshaked(client, e); + } + + private void ThreadHeartbeat(object obj) + { + while (true) + { + if (DisposedValue) + { + return; + } + if (m_client.IsHandshaked && (DateTime.Now.TimeOfDay - m_client.GetLastActiveTime().TimeOfDay > Interval)) + { + if (m_client.Ping()) + { + FailedCount = 0; + } + else + { + FailedCount++; + if (FailedCount > MaxFailCount) + { + m_client.SafeClose("自动心跳失败次数达到最大,已断开连接。"); + } + } + } + + Thread.Sleep(Interval); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs.meta new file mode 100644 index 0000000..5ebb1bc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2de9987e7c806040a3982cf9984146f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs new file mode 100644 index 0000000..367ac7a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc插件基类 + /// + public class TouchRpcPluginBase : TouchRpcPluginBase + { + } + + /// + /// TouchRpc插件基类 + /// + public partial class TouchRpcPluginBase : TcpPluginBase, ITouchRpcPlugin + { + #region 虚函数 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + protected virtual Task OnFileTransferedAsync(TClient client, FileTransferStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + /// + protected virtual Task OnFileTransferingAsync(TClient client, FileOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + /// + protected virtual Task OnHandshakedAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在验证Token时 + /// + /// + /// + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// + /// + /// + protected virtual Task OnHandshakingAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 收到协议数据 + /// + /// + /// + protected virtual void OnReceivedProtocolData(TClient client, ProtocolDataEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual Task OnReceivedProtocolDataAsync(TClient client, ProtocolDataEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + /// + protected virtual Task OnRoutingAsync(TClient client, PackageRouterEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferedAsync(TClient client, StreamStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferingAsync(TClient client, StreamOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + + void ITouchRpcPlugin.OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e) + { + OnFileTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferedAsync(ITouchRpc client, FileTransferStatusEventArgs e) + { + return OnFileTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnFileTransfering(ITouchRpc client, FileOperationEventArgs e) + { + OnFileTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferingAsync(ITouchRpc client, FileOperationEventArgs e) + { + return OnFileTransferingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaked((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakedAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaking((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakingAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + OnReceivedProtocolData((TClient)client, e); + } + + Task ITouchRpcPlugin.OnReceivedProtocolDataAsync(ITouchRpc client, ProtocolDataEventArgs e) + { + return OnReceivedProtocolDataAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + OnRouting((TClient)client, e); + } + + Task ITouchRpcPlugin.OnRoutingAsync(ITouchRpc client, PackageRouterEventArgs e) + { + return OnRoutingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e) + { + OnStreamTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferedAsync(ITouchRpc client, StreamStatusEventArgs e) + { + return OnStreamTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e) + { + OnStreamTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferingAsync(ITouchRpc client, StreamOperationEventArgs e) + { + return OnStreamTransferingAsync((TClient)client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs.meta new file mode 100644 index 0000000..b63706c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94db10a9fcb36594cbabdfa798e8a78b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs new file mode 100644 index 0000000..f98b187 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs @@ -0,0 +1,298 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// WSTouchRpc插件基类 + /// + public partial class WSTouchRpcPluginBase :PluginBase, ITouchRpcPlugin, IDisconnectedPlguin where TClient: IWSTouchRpcClientBase + { + #region 虚函数 + + /// + /// 在断开连接时 + /// + /// + /// + protected virtual void OnDisconnected(TClient client, DisconnectEventArgs e) + { + } + + /// + /// 会话断开后触发 + /// + /// + /// + /// + protected virtual Task OnDisconnectedAsync(TClient client, DisconnectEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + protected virtual Task OnFileTransferedAsync(TClient client, FileTransferStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + /// + protected virtual Task OnFileTransferingAsync(TClient client, FileOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + /// + protected virtual Task OnHandshakedAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在验证Token时 + /// + /// + /// + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// + /// + /// + protected virtual Task OnHandshakingAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 收到协议数据 + /// + /// + /// + protected virtual void OnReceivedProtocolData(TClient client, ProtocolDataEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual Task OnReceivedProtocolDataAsync(TClient client, ProtocolDataEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + /// + protected virtual Task OnRoutingAsync(TClient client, PackageRouterEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferedAsync(TClient client, StreamStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferingAsync(TClient client, StreamOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + + void IDisconnectedPlguin.OnDisconnected(object client, DisconnectEventArgs e) + { + OnDisconnected((TClient)client, e); + } + + Task IDisconnectedPlguin.OnDisconnectedAsync(object client, DisconnectEventArgs e) + { + return OnDisconnectedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e) + { + OnFileTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferedAsync(ITouchRpc client, FileTransferStatusEventArgs e) + { + return OnFileTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnFileTransfering(ITouchRpc client, FileOperationEventArgs e) + { + OnFileTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferingAsync(ITouchRpc client, FileOperationEventArgs e) + { + return OnFileTransferingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaked((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakedAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaking((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakingAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + OnReceivedProtocolData((TClient)client, e); + } + + Task ITouchRpcPlugin.OnReceivedProtocolDataAsync(ITouchRpc client, ProtocolDataEventArgs e) + { + return OnReceivedProtocolDataAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + OnRouting((TClient)client, e); + } + + Task ITouchRpcPlugin.OnRoutingAsync(ITouchRpc client, PackageRouterEventArgs e) + { + return OnRoutingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e) + { + OnStreamTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferedAsync(ITouchRpc client, StreamStatusEventArgs e) + { + return OnStreamTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e) + { + OnStreamTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferingAsync(ITouchRpc client, StreamOperationEventArgs e) + { + return OnStreamTransferingAsync((TClient)client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs.meta new file mode 100644 index 0000000..f7f444c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Plugins/WSTouchRpcPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a189da053544a684b8c005fca89b8c58 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis.meta new file mode 100644 index 0000000..aeab019 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 13a04b31bee35e342883575133926721 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs new file mode 100644 index 0000000..9a03dc0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs @@ -0,0 +1,576 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有远程键值存贮的操作端。 + /// + public abstract class RedisClient : ICache + { + /// + /// 序列化转换器。 + /// + public BytesConverter Converter { get; set; } + + /// + /// 超时设定。默认30000ms + /// + public int Timeout { get; set; } = 30 * 1000; + + /// + /// + /// + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool Add(string key, TValue value, int duration = 60000) + { + var cache = new CacheEntry(key) + { + Duration = TimeSpan.FromSeconds(duration) + }; + if (!(value is byte[])) + { + cache.Value = Converter.ConvertTo(value); + } + return AddCache(cache); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool AddCache(ICacheEntry entity) + { + if (ContainsCache(entity.Key)) + { + return false; + } + else + { + return SetCache(entity); + } + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task AddCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return AddCache(entity); + }); + } + + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract void ClearCache(); + + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task ClearCacheAsync() + { + return EasyTask.Run(() => + { + ClearCache(); + }); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool ContainsCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task ContainsCacheAsync(string key) + { + return EasyTask.Run(() => + { + return ContainsCache(key); + }); + } + + /// + /// 获取缓存的键值对。 + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public TValue Get(string key) + { + if (TryGet(key, out var cache)) + { + return cache; + } + return default; + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract ICacheEntry GetCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task> GetCacheAsync(string key) + { + return EasyTask.Run(() => + { + return GetCache(key); + }); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool RemoveCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task RemoveCacheAsync(string key) + { + return EasyTask.Run(() => + { + return RemoveCache(key); + }); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool Set(string key, TValue value, int duration = 60000) + { + var cache = new CacheEntry(key) + { + Duration = TimeSpan.FromSeconds(duration) + }; + if (value is byte[] bytes) + { + cache.Value = bytes; + } + else + { + cache.Value = Converter.ConvertTo(value); + } + return SetCache(cache); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool SetCache(ICacheEntry entity); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task SetCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return SetCache(entity); + }); + } + + /// + /// 获取指定键的值。 + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool TryGet(string key, out TValue value) + { + var cache = GetCache(key); + + if (cache != null) + { + if (cache.Value is null) + { + value = default; + return true; + } + if (cache.Value is TValue value1) + { + value = value1; + return true; + } + value = (TValue)Converter.ConvertFrom(cache.Value, typeof(TValue)); + return true; + } + value = default; + return false; + } + } + + /// + /// RedisClient + /// + internal class InternalRedisClient : RedisClient + { + private readonly RpcActor m_rpcActor; + + public InternalRedisClient(RpcActor rpcActor, BytesConverter converter) + { + m_rpcActor = rpcActor; + Converter = converter; + } + + public override void ClearCache() + { + var package = new RedisRequestWaitPackage + { + packageType = RedisPackageType.Clear + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock()) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool ContainsCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + var package = new RedisRequestWaitPackage + { + key = key, + packageType = RedisPackageType.Contains + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock()) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override ICacheEntry GetCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + RedisRequestWaitPackage package = new RedisRequestWaitPackage() + { + key = key, + packageType = RedisPackageType.Get + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + RedisResponseWaitPackage responsePackage = (RedisResponseWaitPackage)waitData.WaitResult; + if (responsePackage.Status == 1) + { + return new CacheEntry(key) + { + Value = responsePackage.value + }; + } + else if (responsePackage.Status == byte.MaxValue) + { + return new CacheEntry(key); + } + else + { + return default; + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool RemoveCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + var package = new RedisRequestWaitPackage + { + key = key, + packageType = RedisPackageType.Remove + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: return false; + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool SetCache(ICacheEntry cache) + { + if (string.IsNullOrEmpty(cache.Key)) + { + throw new ArgumentException($"“{nameof(cache.Key)}”不能为 null 或空。", nameof(cache.Key)); + } + + if (cache is null) + { + throw new ArgumentNullException(nameof(cache)); + } + + var package = new RedisRequestWaitPackage + { + key = cache.Key, + timeSpan = cache.Duration, + value = cache.Value, + packageType = RedisPackageType.Set + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: return false; + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs.meta new file mode 100644 index 0000000..15ab654 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6b2805dc92e84e4d9e4c7cf67e5cbe4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs new file mode 100644 index 0000000..14b1c25 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RedisClientExtensions + /// + public static class RedisClientExtensions + { + /// + /// 获取或设置RedisClient的注入键。 + /// + public static readonly DependencyProperty RedisClientProperty = + DependencyProperty.Register("RedisClient", typeof(RedisClientExtensions), null); + + /// + /// 获取RedisClient + /// + /// + /// + /// + /// + public static RedisClient GetRedisClient(this TClient client) where TClient : IDependencyTouchRpc, IDependencyObject + { + return client.GetValue(RedisClientProperty); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs.meta new file mode 100644 index 0000000..3b9217b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3915a826a89b95f4db6392dac9823423 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs new file mode 100644 index 0000000..422d89e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.TouchRpc +{ + internal enum RedisPackageType : byte + { + Set, + Get, + Contains, + Remove, + Clear + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs.meta new file mode 100644 index 0000000..9f312cb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10e7311b2e8347c41bd3f4429fb689bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs new file mode 100644 index 0000000..74e849a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RedisPlugin + /// + public class RedisPlugin : TouchRpcPluginBase + { + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + public BytesConverter Converter { get; private set; } = new BytesConverter(); + + /// + /// 实际储存缓存。 + /// + public ICache ICache { get; set; } = new MemoryCache(); + + /// + /// 设置实际储存缓存。 + /// + /// + public void SetCache(ICache cache) + { + ICache = cache; + } + + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + /// + public void SetConverter(BytesConverter converter) + { + Converter = converter; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(IDependencyTouchRpc client, VerifyOptionEventArgs e) + { + client.SetValue(RedisClientExtensions.RedisClientProperty, new InternalRedisClient(client.RpcActor, Converter)); + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(IDependencyTouchRpc client, ProtocolDataEventArgs e) + { + switch (e.Protocol) + { + case TouchRpcUtility.P_600_Redis_Request: + { + var waitResult = new RedisResponseWaitPackage(); + try + { + e.Handled = true; + RedisRequestWaitPackage package = new RedisRequestWaitPackage(); + package.Unpackage(e.ByteBlock.Seek(2)); + waitResult.Sign = package.Sign; + + switch (package.packageType) + { + case RedisPackageType.Set: + { + bool success = ICache.SetCache(new CacheEntry(package.key) + { + Duration = package.timeSpan.Value, + Value = package.value + }); + if (success) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + break; + } + case RedisPackageType.Get: + { + var cache = ICache.GetCache(package.key); + if (cache != null) + { + waitResult.Status = 1; + waitResult.value = cache.Value; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Contains: + { + if (ICache.ContainsCache(package.key)) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Remove: + { + if (ICache.RemoveCache(package.key)) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Clear: + { + ICache.ClearCache(); + waitResult.Status = 1; + } + break; + + default: + return; + } + } + catch (Exception ex) + { + waitResult.Status = 2; + waitResult.Message = ex.Message; + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + waitResult.Package(byteBlock); + client.Send(TouchRpcUtility.P_1600_Redis_Response, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + } + + case TouchRpcUtility.P_1600_Redis_Response: + { + e.Handled = true; + var waitResult = new RedisResponseWaitPackage(); + waitResult.Unpackage(e.ByteBlock.Seek(2)); + client.RpcActor.WaitHandlePool.SetRun(waitResult); + break; + } + default: + break; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs.meta new file mode 100644 index 0000000..1d31699 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d6dcd0d4ade05f4db4ea6db9ebf81ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs new file mode 100644 index 0000000..1d6ff95 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class RedisRequestWaitPackage : RedisResponseWaitPackage + { + public string key; + public TimeSpan? timeSpan; + public RedisPackageType packageType; + + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(key); + byteBlock.Write((byte)packageType); + if (timeSpan.HasValue) + { + byteBlock.Write((byte)1); + byteBlock.Write(timeSpan.Value); + } + else + { + byteBlock.Write((byte)0); + } + } + + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + key = byteBlock.ReadString(); + packageType = (RedisPackageType)byteBlock.ReadByte(); + if (byteBlock.ReadByte() == 1) + { + timeSpan = byteBlock.ReadTimeSpan(); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs.meta new file mode 100644 index 0000000..f368016 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82839939b609b0f46acec948d57bab5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs new file mode 100644 index 0000000..83eaccf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class RedisResponseWaitPackage : WaitPackage + { + public byte[] value; + + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.WriteBytesPackage(value); + } + + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + value = byteBlock.ReadBytesPackage(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs.meta new file mode 100644 index 0000000..68534fc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 133a7e013dbde614a8ebb30b89456cc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc.meta new file mode 100644 index 0000000..b76c484 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 758a8292d3b862b42bdf328ee6d7972b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs new file mode 100644 index 0000000..7ca4b5c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class CanceledPackage : RouterPackage + { + public long Sign { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + byteBlock.Write(Sign); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + Sign = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs.meta new file mode 100644 index 0000000..e888dc1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e8b683b289032949b43f7f22f11c934 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs new file mode 100644 index 0000000..e1e7d73 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc调用设置 + /// + public struct InvokeOption : IInvokeOption + { + /// + /// 默认设置。 + /// Timeout=5000ms + /// + public static InvokeOption OnlySend; + + /// + /// 默认设置。 + /// Timeout=5000ms + /// + public static InvokeOption WaitInvoke; + + /// + /// 默认设置。 + /// Timeout=5000 ms + /// + public static InvokeOption WaitSend; + + private int m_timeout; + + static InvokeOption() + { + OnlySend = new InvokeOption(timeout: 5000); + OnlySend.FeedbackType = FeedbackType.OnlySend; + + WaitSend = new InvokeOption(timeout: 5000); + WaitSend.FeedbackType = FeedbackType.WaitSend; + + WaitInvoke = new InvokeOption(timeout: 5000); + WaitInvoke.FeedbackType = FeedbackType.WaitInvoke; + } + + /// + /// 构造函数 + /// + /// + /// + /// + /// + public InvokeOption(int timeout = 5000, FeedbackType feedbackType = FeedbackType.WaitInvoke, SerializationType serializationType = SerializationType.FastBinary, + CancellationToken cancellationToken = default) : this() + { + Timeout = timeout; + FeedbackType = feedbackType; + SerializationType = serializationType; + Token = cancellationToken; + } + + /// + /// 调用反馈 + /// + public FeedbackType FeedbackType { get; set; } + + /// + /// TouchRpc序列化类型 + /// + public SerializationType SerializationType { get; set; } + + /// + /// 调用超时, + /// min=1000,默认5000 ms + /// + public int Timeout + { + get + { + if (m_timeout < 1000) + { + return 5000; + } + return m_timeout; + } + set => m_timeout = value; + } + + /// + /// 可以取消的调用令箭 + /// + public CancellationToken Token { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs.meta new file mode 100644 index 0000000..f658e86 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f5d42c2b6019f8439eb2c68621314bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization.meta new file mode 100644 index 0000000..38393d1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b1039ede681c6b4a8e38e3b11838e51 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs new file mode 100644 index 0000000..d171c19 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 默认序列化选择器 + /// + public class DefaultSerializationSelector : SerializationSelector + { + /// + /// 反序列化 + /// + /// + /// + /// + /// + public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType) + { + if (parameterBytes == null) + { + return parameterType.GetDefault(); + } + switch (serializationType) + { + case SerializationType.FastBinary: + { + return SerializeConvert.FastBinaryDeserialize(parameterBytes, 0, parameterType); + } + case SerializationType.SystemBinary: + { + return SerializeConvert.BinaryDeserialize(parameterBytes, 0, parameterBytes.Length); + } + case SerializationType.Json: + { + return Encoding.UTF8.GetString(parameterBytes).FromJson(parameterType); + } + case SerializationType.Xml: + { + return SerializeConvert.XmlDeserializeFromBytes(parameterBytes, parameterType); + } + default: + throw new RpcException("未指定的反序列化方式"); + } + } + + /// + /// 序列化参数 + /// + /// + /// + /// + public override byte[] SerializeParameter(SerializationType serializationType, object parameter) + { + if (parameter == null) + { + return null; + } + switch (serializationType) + { + case SerializationType.FastBinary: + { + return SerializeConvert.FastBinarySerialize(parameter); + } + case SerializationType.SystemBinary: + { + return SerializeConvert.BinarySerialize(parameter); + } + case SerializationType.Json: + { + return SerializeConvert.JsonSerializeToBytes(parameter); + } + case SerializationType.Xml: + { + return SerializeConvert.XmlSerializeToBytes(parameter); + } + default: + throw new RpcException("未指定的序列化方式"); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs.meta new file mode 100644 index 0000000..e1c6420 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66ad341e8b5c9b84ab58e7b2947b0a4f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs new file mode 100644 index 0000000..89c6d21 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 序列化选择器 + /// + public abstract class SerializationSelector + { + /// + /// 序列化Rpc方法返回值参数 + /// + /// + /// + /// + public abstract byte[] SerializeParameter(SerializationType serializationType, object parameter); + + /// + /// 反序列化传输对象 + /// + /// + /// + /// + /// + public abstract object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs.meta new file mode 100644 index 0000000..11e2bae --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d58640b12375fa5479c24e66ccad9375 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs new file mode 100644 index 0000000..cb1b946 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc上下文 + /// + internal class TouchRpcCallContext : ITouchRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// 当不为空时,调用 + /// + /// + public bool TryCancel() + { + if (m_tokenSource != null) + { + m_tokenSource.Cancel(); + return true; + } + return false; + } + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// 能取消的调用令箭,在客户端主动取消或网络故障时生效 + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// TouchRpcContext + /// + public TouchRpcPackage TouchRpcPackage { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType => TouchRpcPackage == null ? (SerializationType)byte.MaxValue : TouchRpcPackage.SerializationType; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs.meta new file mode 100644 index 0000000..611368f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a53d174526510444c8aa5896612e8f1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs new file mode 100644 index 0000000..82485d9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc传输类 + /// + public sealed class TouchRpcPackage : WaitRouterPackage + { + /// + /// 反馈类型 + /// + public FeedbackType Feedback { get; private set; } + + /// + /// 参数是否包含引用类型 + /// + public bool IsByRef { get; internal set; } + + /// + /// 函数名 + /// + public string MethodName { get; internal set; } + + /// + /// 参数数据 + /// + public List ParametersBytes { get; internal set; } + + /// + /// 返回参数数据 + /// + public byte[] ReturnParameterBytes { get; internal set; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType { get; private set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write((byte)SerializationType); + byteBlock.Write((byte)Feedback); + byteBlock.Write(IsByRef); + byteBlock.Write(MethodName); + byteBlock.WriteBytesPackage(ReturnParameterBytes); + + if (ParametersBytes != null && ParametersBytes.Count > 0) + { + byteBlock.Write((byte)ParametersBytes.Count); + foreach (byte[] item in ParametersBytes) + { + byteBlock.WriteBytesPackage(item); + } + } + else + { + byteBlock.Write((byte)0); + } + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + SerializationType = (SerializationType)byteBlock.ReadByte(); + Feedback = (FeedbackType)byteBlock.ReadByte(); + IsByRef = byteBlock.ReadBoolean(); + MethodName = byteBlock.ReadString(); + ReturnParameterBytes = byteBlock.ReadBytesPackage(); + + byte countPar = (byte)byteBlock.ReadByte(); + ParametersBytes = new List(); + for (int i = 0; i < countPar; i++) + { + ParametersBytes.Add(byteBlock.ReadBytesPackage()); + } + } + + internal void LoadInvokeOption(IInvokeOption option) + { + InvokeOption invokeOption = (InvokeOption)option; + Feedback = invokeOption.FeedbackType; + SerializationType = invokeOption.SerializationType; + } + + internal void ThrowStatus() + { + if (Status == 1) + { + return; + } + switch (Status.ToStatus()) + { + case TouchSocketStatus.ClientNotFind: + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(TargetId)); + } + case TouchSocketStatus.UnknownError: + case TouchSocketStatus.RpcMethodNotFind: + case TouchSocketStatus.RpcMethodDisable: + case TouchSocketStatus.RemoteRefuse: + case TouchSocketStatus.RpcInvokeException: + case TouchSocketStatus.RoutingNotAllowed: + case TouchSocketStatus.Exception: + default: + { + throw new RpcException(Status.ToStatus().GetDescription(Message)); + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs.meta new file mode 100644 index 0000000..bb6dc15 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04f175587ac30734b8be7e6ca6927f54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs new file mode 100644 index 0000000..6a815c8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Udp调用者 + /// + public class UdpCaller + { + private readonly EndPoint callerEndPoint; + + private readonly UdpSessionBase m_service; + + /// + /// 构造函数 + /// + /// + /// + public UdpCaller(UdpSessionBase service, EndPoint callerEndPoint) + { + m_service = service; + this.callerEndPoint = callerEndPoint; + } + + /// + /// 调用者终结点 + /// + public EndPoint CallerEndPoint => callerEndPoint; + + /// + /// Udp服务器 + /// + public UdpSessionBase Service => m_service; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs.meta new file mode 100644 index 0000000..0aa552f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d52b4ebf52abea64d9c44582cb2dcdcb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor.meta new file mode 100644 index 0000000..8f33cf6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 645eff142ed509949935f8441a440cf9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface.meta new file mode 100644 index 0000000..3afa172 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e30822b172b92845bb4aeb0fc0b05ed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs new file mode 100644 index 0000000..3ab79b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IDRpcActor + /// + public class IDRpcActor : IRpcClient + { + private readonly string m_targetId; + private readonly IRpcActor m_rpcActor; + + /// + /// 构造函数 + /// + /// + /// + public IDRpcActor(string targetId, IRpcActor rpcActor) + { + m_targetId = targetId; + m_rpcActor = rpcActor; + } + + /// + /// + /// + public Func TryCanInvoke { get => m_rpcActor.TryCanInvoke; set => m_rpcActor.TryCanInvoke = value; } + + /// + /// + /// + public void Dispose() + { + m_rpcActor.Dispose(); + } + + /// + /// + /// + /// + /// + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, ref parameters, types); + } + + /// + /// + /// + /// + /// + /// + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, ref parameters, types); + } + + /// + /// + /// + /// + /// + /// + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(m_targetId, invokeKey, invokeOption, parameters); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs.meta new file mode 100644 index 0000000..e9e5aa0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d75420018f71ec64db7b00d0f20533e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs new file mode 100644 index 0000000..83919c0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActor接口 + /// + public partial interface IRpcActor : IRpcActorBase, IRpcClient, ITargetRpcActor + { + /// + /// 表示是否已经完成握手连接。 + /// + bool IsHandshaked { get; } + + /// + /// 根路径 + /// + string RootPath { get; set; } + + /// + /// 判断使用该ID的Channel是否存在。 + /// + /// + /// + bool ChannelExisted(int id); + + /// + /// 创建通道 + /// + /// + /// + Channel CreateChannel(); + + /// + /// 创建通道 + /// + /// 指定ID + /// + /// + Channel CreateChannel(int id); + + /// + /// 从对点拉取文件 + /// + /// + /// + Result PullFile(FileOperator fileOperator); + + /// + /// 异步从对点拉取文件 + /// + /// + /// + Task PullFileAsync(FileOperator fileOperator); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 向对点推送文件 + /// + /// + /// + Result PushFile(FileOperator fileOperator); + + /// + /// 异步向对点推送文件 + /// + /// + /// + Task PushFileAsync(FileOperator fileOperator); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 重新设置ID + /// + /// + void ResetID(string newId); + + /// + /// 发送流数据 + /// + /// + /// + /// + /// + Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = default); + + /// + /// 异步发送流数据 + /// + /// + /// + /// + /// + Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = default); + + /// + /// 订阅通道 + /// + /// + /// + /// + bool TrySubscribeChannel(int id, out Channel channel); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs.meta new file mode 100644 index 0000000..49722ff --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61f98bc79fafc80408b7a096eb61631f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs new file mode 100644 index 0000000..830eadc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorBase + /// + public interface IRpcActorBase:IRpcActorSender + { + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 序列化选择器 + /// + SerializationSelector SerializationSelector { get; } + + /// + /// 向通信的对方执行ping。 + /// + /// + /// 如果返回True,则表示一定在线。如果返回false,则不一定代表不在线。 + bool Ping(int timeout = 5000); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs.meta new file mode 100644 index 0000000..718011f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68e5de2783d5cac4891c9a2650ec79e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs new file mode 100644 index 0000000..e4b2c65 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 带有协议的发送 + /// + public interface IRpcActorSender + { + /// + /// 发送字节 + /// + /// + /// + /// + /// + void Send(short protocol, byte[] buffer, int offset, int length); + + /// + /// 发送字节 + /// + /// + /// + /// + /// + Task SendAsync(short protocol, byte[] buffer, int offset, int length); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs.meta new file mode 100644 index 0000000..97fb66a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2296b99f7e0a4ca4cad05ad951306e82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs new file mode 100644 index 0000000..9e239b4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITargetRpcActor + /// + public partial interface ITargetRpcActor : ITargetRpcClient + { + /// + /// 创建一个和其他客户端的通道 + /// + /// 目标客户端ID + /// + /// + public Channel CreateChannel(string targetId); + + /// + /// 创建一个和其他客户端的通道 + /// + /// 目标客户端ID + /// 通道Id + /// + /// + public Channel CreateChannel(string targetId, int id); + + /// + /// 向指定的Id执行ping。 + /// + /// 目标客户端ID + /// 超时配置 + /// 如果返回True,则表示一定在线。如果返回false,则不一定代表不在线。 + bool Ping(string targetId, int timeout = 5000); + + #region 文件传输 + + /// + /// 从对点拉取文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Result PullFile(string targetId, FileOperator fileOperator); + + /// + /// 异步从对点拉取文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Task PullFileAsync(string targetId, FileOperator fileOperator); + + /// + /// 向对点推送文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Result PushFile(string targetId, FileOperator fileOperator); + + /// + /// 异步向对点推送文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Task PushFileAsync(string targetId, FileOperator fileOperator); + + #endregion 文件传输 + + #region 小文件 + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 目标客户端ID + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 目标客户端Id + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件到特定的Id。默认设置1024*1024字节大小。 + /// + /// 目标客户端Id + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs.meta new file mode 100644 index 0000000..3961abe --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ff014cbea3c36b4898bd70ea92ffd87 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs new file mode 100644 index 0000000..be37319 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITargetRpcClient + /// + public interface ITargetRpcClient + { + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs.meta new file mode 100644 index 0000000..7fa8150 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3420457b64424634bbbb1f113061a31f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs new file mode 100644 index 0000000..9f38ec1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs @@ -0,0 +1,228 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_userChannels; + + /// + /// + /// + /// + /// + public bool ChannelExisted(int id) + { + return m_userChannels.ContainsKey(id); + } + + /// + public Channel CreateChannel() + { + return this.PrivateCreateChannel(default, true); + } + + /// + public Channel CreateChannel(int id) + { + return this.PrivateCreateChannel(default, false, id); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.CreateChannel(id); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivateCreateChannel(targetId, false, id); + } + + private Channel PrivateCreateChannel(string targetId, bool random, int id = 0) + { + lock (SyncRoot) + { + if (random) + { + id = new object().GetHashCode(); + } + else + { + if (ChannelExisted(id)) + { + throw new Exception(TouchSocketStatus.ChannelExisted.GetDescription(id)); + } + } + + ByteBlock byteBlock = new ByteBlock(); + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage() + { + Random = random, + ChannelID = id, + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue() + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitCreateChannel); + + try + { + waitCreateChannel.Package(byteBlock); + Send(TouchRpcUtility.P_100_CreateChannel_Request, byteBlock); + switch (waitData.Wait(10 * 1000)) + { + case WaitDataStatus.SetRunning: + { + WaitCreateChannelPackage result = (WaitCreateChannelPackage)waitData.WaitResult; + switch (result.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + InternalChannel channel = new InternalChannel(this, targetId); + channel.SetID(result.ChannelID); + channel.SetUsing(); + if (m_userChannels.TryAdd(result.ChannelID, channel)) + { + return channel; + } + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + case TouchSocketStatus.ClientNotFind: + { + throw new Exception(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + case TouchSocketStatus.RoutingNotAllowed: + default: + { + throw new Exception(result.Status.ToStatus().GetDescription(result.Message)); + } + } + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + } + default: + { + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + } + + internal void SendChannelPackage(ChannelPackage channelPackage) + { + using (ByteBlock byteBlock = new ByteBlock(channelPackage.GetLen())) + { + channelPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock); + } + } + + /// + public Channel CreateChannel(string targetId) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.CreateChannel(); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivateCreateChannel(targetId, true); + } + + internal bool RemoveChannel(int id) + { + return m_userChannels.TryRemove(id, out _); + } + + /// + /// 订阅通道 + /// + /// + /// + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + if (m_userChannels.TryGetValue(id, out InternalChannel channelOut)) + { + if (channelOut.Using) + { + channel = null; + return false; + } + channelOut.SetUsing(); + channel = channelOut; + return true; + } + channel = null; + return false; + } + + private bool QueueChannelPackage(ChannelPackage channelPackage) + { + if (m_userChannels.TryGetValue(channelPackage.ChannelId, out InternalChannel channel)) + { + channel.ReceivedData(channelPackage); + return true; + } + + return false; + } + + private bool RequestCreateChannel(int id, string targetId) + { + lock (SyncRoot) + { + InternalChannel channel = new InternalChannel(this, targetId); + channel.SetID(id); + if (m_userChannels.TryAdd(id, channel)) + { + return true; + } + else + { + channel.SafeDispose(); + return false; + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs.meta new file mode 100644 index 0000000..6ecf4cc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 142175c05dd8318449c5de88eeffe610 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs new file mode 100644 index 0000000..e2350c7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs @@ -0,0 +1,1220 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_eventArgs; + private string m_rootPath = string.Empty; + + /// + public string RootPath + { + get => m_rootPath; + set + { + value ??= string.Empty; + m_rootPath = value; + } + } + + #region Pull + + /// + public Result PullFile(FileOperator fileOperator) + { + return this.PrivatePullFile(default, fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PullFile(fileOperator); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + + return this.PrivatePullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PullFile(targetId, fileOperator); + }); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PullFile(fileOperator); + }); + } + + private Result PreviewPullFile(string targetId, FileOperator fileOperator, WaitFileInfoPackage waitFileInfoPackage) + { + TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo; + fileOperator.SavePath = FileController.GetFullPath(m_rootPath, fileOperator.SavePath); + TouchRpcFileStream stream; + try + { + FileController.TryReadTempInfo(fileOperator.SavePath, fileOperator.Flags, ref fileInfo); + stream = TouchRpcFileStream.Create(fileOperator.SavePath, ref fileInfo, fileOperator.Flags.HasFlag(TransferFlags.BreakpointResume)); + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + + WaitTransferPackage waitTransfer = new WaitTransferPackage() + { + EventHashCode = waitFileInfoPackage.EventHashCode, + Path = fileInfo.FullName, + Position = fileInfo.Position, + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue() + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitTransfer); + ByteBlock byteBlock = new ByteBlock(); + Channel channel = default; + try + { + if (targetId == null) + { + channel = CreateChannel(); + } + else + { + channel = CreateChannel(targetId); + } + waitTransfer.ChannelID = channel.ID; + waitTransfer.Package(byteBlock); + Send(TouchRpcUtility.P_501_BeginPullFile_Request, byteBlock); + + if (fileOperator.Token.IsCancellationRequested) + { + waitData.SetCancellationToken(fileOperator.Token); + } + + switch (waitData.Wait(fileOperator.Timeout)) + { + case WaitDataStatus.SetRunning: + { + WaitTransferPackage waitTransferResult = (WaitTransferPackage)waitData.WaitResult; + switch (waitTransferResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + fileOperator.SetFileCompletedLength(fileInfo.Position); + fileOperator.SetLength(fileInfo.Length); + channel.Timeout = fileOperator.Timeout; + while (channel.MoveNext()) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + byte[] data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + fileInfo.Position = stream.FileWriter.Position; + fileOperator.AddFlow(data.Length); + } + } + + if (channel.Status == ChannelStatus.Completed) + { + stream.FinishStream(); + return fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + return fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + case TouchSocketStatus.LoadStreamFail: + return fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.LoadStreamFail.GetDescription(fileInfo.FullName))); + + default: + return fileOperator.SetResult(new Result(ResultCode.Error, waitTransferResult.Status.ToStatus().GetDescription(waitTransferResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + WaitHandlePool.Destroy(waitData); + stream.SafeDispose(); + byteBlock.Dispose(); + channel.SafeDispose(); + } + } + + private Result PrivatePullFile(string targetId, FileOperator fileOperator) + { + if (fileOperator is null) + { + return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator))); + } + + WaitFileInfoPackage waitFileInfo = new WaitFileInfoPackage + { + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue(), + Metadata = fileOperator.Metadata, + SavePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.SavePath), + Flags = fileOperator.Flags, + ResourcePath = fileOperator.ResourcePath + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitFileInfo); + + ByteBlock byteBlock = new ByteBlock(); + try + { + waitFileInfo.Package(byteBlock); + Send(TouchRpcUtility.P_500_PullFile_Request, byteBlock); + + if (fileOperator.Token.IsCancellationRequested) + { + waitData.SetCancellationToken(fileOperator.Token); + } + + waitData.Wait(fileOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitFileInfoPackage waitFileResult = (WaitFileInfoPackage)waitData.WaitResult; + switch (waitFileResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + return PreviewPullFile(targetId, fileOperator, waitFileResult); + + case TouchSocketStatus.FileNotExists: + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFileResult.ResourcePath))); + + case TouchSocketStatus.RemoteRefuse: + default: + return fileOperator.SetResult(new Result(ResultCode.Fail, waitFileResult.Status.ToStatus().GetDescription(waitFileResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(Result.Overtime); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(Result.Canceled); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(Result.UnknownFail); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ex)); + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + #endregion Pull + + #region Push + + /// + public Result PushFile(FileOperator fileOperator) + { + return PrivatePushFile(default, fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PushFile(fileOperator); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivatePushFile(default, fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PushFile(targetId, fileOperator); + }); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PushFile(fileOperator); + }); + } + + private Result PreviewPushFile(FileOperator fileOperator, WaitTransferPackage waitTransfer) + { + try + { + using FileStorageReader reader = FilePool.GetReader(waitTransfer.Path); + fileOperator.SetLength(reader.FileStorage.FileInfo.Length); + if (TrySubscribeChannel(waitTransfer.ChannelID, out Channel channel)) + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + try + { + long position = waitTransfer.Position; + reader.Position = position; + fileOperator.SetFileCompletedLength(waitTransfer.Position); + + channel.Timeout = fileOperator.Timeout; + while (true) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel("主动取消"); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + int r = reader.Read(byteBlock.Buffer, 0, (int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0)); + if (r == 0) + { + channel.Complete(); + WaitPushFileAckPackage waitResult = null; + if (SpinWait.SpinUntil(() => + { + if (m_eventArgs.TryRemove(waitTransfer.EventHashCode, out object obj)) + { + waitResult = (WaitPushFileAckPackage)obj; + return true; + } + return false; + }, fileOperator.Timeout)) + { + if (waitResult.Status.ToStatus() == TouchSocketStatus.Success) + { + return fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Message)); + } + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Overtime, "等待最后状态确认超时。")); + } + } + else + { + position += r; + if (channel.TryWrite(byteBlock.Buffer, 0, r)) + { + fileOperator.AddFlow(r); + } + else + { + break; + } + } + } + if (channel.Status == ChannelStatus.Cancel && !string.IsNullOrEmpty(channel.LastOperationMes)) + { + return fileOperator.SetResult(new Result(ResultCode.Canceled, channel.LastOperationMes)); + } + else + { + return fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + byteBlock.Dispose(); + } + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.SetChannelFail.GetDescription())); + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitTransfer.Path, ex.Message))); + } + } + + private Result PrivatePushFile(string targetId, FileOperator fileOperator) + { + if (fileOperator is null) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator)))); + } + + string fullPath = FileController.GetFullPath(m_rootPath, fileOperator.ResourcePath); + + if (!File.Exists(fullPath)) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath))); + } + + TouchRpcFileInfo fileInfo = new TouchRpcFileInfo(); + try + { + FileController.GetFileInfo(fullPath, fileOperator.Flags.HasFlag(TransferFlags.MD5Verify), ref fileInfo); + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage() + { + FileInfo = fileInfo, + Metadata = fileOperator.Metadata, + ResourcePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.ResourcePath), + SavePath = fileOperator.SavePath, + Flags = fileOperator.Flags, + TargetId = targetId, + SourceId = this.ID, + Route = targetId.HasValue() + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitFileInfoPackage); + + try + { + SendPackage(TouchRpcUtility.P_502_PushFile_Request, waitFileInfoPackage); + waitData.SetCancellationToken(fileOperator.Token); + + waitData.Wait(fileOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitTransferPackage waitResult = (WaitTransferPackage)waitData.WaitResult; + switch (waitResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + return PreviewPushFile(fileOperator, waitResult); + + case TouchSocketStatus.LoadStreamFail: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitResult.Path, waitResult.Message))); + } + case TouchSocketStatus.ClientNotFind: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + case TouchSocketStatus.DirectoryNotExists: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.DirectoryNotExists.GetDescription(waitResult.Path))); + } + case TouchSocketStatus.RemoteRefuse: + default: + return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Status.ToStatus().GetDescription(waitResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ex)); + } + finally + { + WaitHandlePool.Destroy(waitData); + } + } + + #endregion Push + + #region 小文件传输 + + /// + /// 允许传输的小文件的最大长度。默认1024*1024字节。 + /// 注意,当调整该值时,应该和对端保持一致。 + /// + public int MaxSmallFileLength { get; set; } = 1024 * 1024; + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.PullSmallFile(path, metadata, timeout, token); + } + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + + return PrivatePullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return PrivatePullSmallFile(default, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PullSmallFile(targetId, path, metadata, timeout, token); + }); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PullSmallFile(path, metadata, timeout, token); + }); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + return PrivatePushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return PrivatePushSmallFile(default, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + }); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PushSmallFile(savePath, fileInfo, metadata, timeout, token); + }); + } + + private PullSmallFileResult PrivatePullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage() + { + Path = path, + SourceId = ID, + TargetId = targetId, + Route = targetId.HasValue(), + Metadata = metadata + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage); + + ByteBlock byteBlock = new ByteBlock(); + try + { + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_517_PullSmallFile_Request, byteBlock); + waitData.SetCancellationToken(token); + + waitData.Wait(timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult; + switch (waitFile.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + return new PullSmallFileResult(waitFile.Data); + } + case TouchSocketStatus.FileNotExists: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFile.Path)); + } + case TouchSocketStatus.RemoteRefuse: + case TouchSocketStatus.LengthErrorWhenRead: + case TouchSocketStatus.FileLengthTooLong: + case TouchSocketStatus.ClientNotFind: + default: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message)); + } + } + } + case WaitDataStatus.Overtime: + { + return new PullSmallFileResult(ResultCode.Overtime); + } + case WaitDataStatus.Canceled: + { + return new PullSmallFileResult(ResultCode.Canceled); + } + case WaitDataStatus.Disposed: + default: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + private Result PrivatePushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (!File.Exists(fileInfo.FullName)) + { + return new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fileInfo.FullName)); + } + if (fileInfo.Length > MaxSmallFileLength) + { + return new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription()); + } + WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage() + { + Path = savePath, + SourceId = ID, + Metadata = metadata, + Route = targetId.HasValue(), + TargetId = targetId, + FileInfo = new RemoteFileInfo(fileInfo) + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage); + + ByteBlock byteBlock = new ByteBlock(); + byte[] buffer = BytePool.Default.GetByteCore((int)fileInfo.Length); + try + { + int r = FileController.ReadAllBytes(fileInfo, buffer); + if (r <= 0) + { + return new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription()); + } + waitSmallFilePackage.Data = buffer; + waitSmallFilePackage.Len = r; + + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_518_PushSmallFile_Request, byteBlock); + waitData.SetCancellationToken(token); + + waitData.Wait(timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult; + switch (waitFile.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + return Result.Success; + } + case TouchSocketStatus.RemoteRefuse: + { + return new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message)); + } + case TouchSocketStatus.ClientNotFind: + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + default: + return new Result(ResultCode.Exception, waitFile.Message); + } + } + case WaitDataStatus.Overtime: + { + return Result.Overtime; + } + case WaitDataStatus.Canceled: + { + return Result.Canceled; + } + case WaitDataStatus.Disposed: + default: + { + return Result.UnknownFail; + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + BytePool.Default.Recycle(buffer); + } + } + + private void RequestPullSmallFile(object o) + { + //2.不响应 + //3.不允许 + //4.不存在 + //5.读取文件长度异常 + + byte[] buffer = BytePool.Default.GetByteCore(MaxSmallFileLength); + try + { + WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o; + Result resultThis = Result.Success; + try + { + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPull, + waitSmallFilePackage.Metadata, default) + { + ResourcePath = waitSmallFilePackage.Path + }; + + OnFileTransfering?.Invoke(this, args); + + string fullPath = FileController.GetFullPath(RootPath, args.ResourcePath); + waitSmallFilePackage.Path = fullPath; + if (args.IsPermitOperation) + { + if (File.Exists(fullPath)) + { + FileInfo fileInfo = new FileInfo(fullPath); + if (fileInfo.Length > MaxSmallFileLength) + { + waitSmallFilePackage.Status = TouchSocketStatus.FileLengthTooLong.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription()); + } + else + { + int r = FileController.ReadAllBytes(fileInfo, buffer); + if (r > 0) + { + waitSmallFilePackage.Data = buffer; + waitSmallFilePackage.Len = r; + waitSmallFilePackage.FileInfo = new RemoteFileInfo(fileInfo); + waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue(); + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.LengthErrorWhenRead.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription()); + } + } + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.FileNotExists.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath)); + } + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + waitSmallFilePackage.Message = args.Message; + resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message)); + } + } + catch (Exception ex) + { + waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue(); + waitSmallFilePackage.Message = ex.Message; + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1517_PullSmallFile_Response, byteBlock); + } + + FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs( + TransferType.SmallPull, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis) + { + ResourcePath = waitSmallFilePackage.Path + }; + OnFileTransfered?.Invoke(this, resultArgs); + } + catch + { + } + finally + { + BytePool.Default.Recycle(buffer); + } + } + + private void RequestPushSmallFile(object o) + { + //2.不响应 + //3.不允许 + + try + { + WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o; + Result resultThis = Result.Success; + try + { + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPush, + waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo) + { + SavePath = waitSmallFilePackage.Path + }; + + OnFileTransfering?.Invoke(this, args); + + string fullPath = FileController.GetFullPath(RootPath, args.SavePath); + waitSmallFilePackage.Path = fullPath; + if (args.IsPermitOperation) + { + FileInfo fileInfo = new FileInfo(fullPath); + FileController.WriteAllBytes(fileInfo, waitSmallFilePackage.Data, 0, waitSmallFilePackage.Data.Length); + waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue(); + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + waitSmallFilePackage.Message = args.Message; + resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message)); + } + } + catch (Exception ex) + { + waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue(); + waitSmallFilePackage.Message = ex.Message; + } + waitSmallFilePackage.FileInfo = default; + waitSmallFilePackage.Data = default; + waitSmallFilePackage.SwitchId(); + using (ByteBlock byteBlock = new ByteBlock()) + { + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock); + } + + FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs( + TransferType.SmallPush, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis) + { + SavePath = waitSmallFilePackage.Path + }; + OnFileTransfered?.Invoke(this, resultArgs); + } + catch + { + } + } + + #endregion 小文件传输 + + private void BeginPullFile(object o) + { + try + { + WaitTransferPackage waitTransferPackage = (WaitTransferPackage)o; + FileTransferStatusEventArgs e; + if (m_eventArgs.TryRemove(waitTransferPackage.EventHashCode, out object obj) && obj is FileOperationEventArgs args) + { + try + { + using (FileStorageReader reader = FilePool.GetReader(waitTransferPackage.Path)) + { + if (TrySubscribeChannel(waitTransferPackage.ChannelID, out Channel channel)) + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + FileOperator fileOperator = args.FileOperator; + fileOperator.SetLength(reader.FileStorage.FileInfo.Length); + try + { + waitTransferPackage.Status = TouchSocketStatus.Success.ToValue(); + waitTransferPackage.SwitchId(); + SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage); + long position = waitTransferPackage.Position; + reader.Position = position; + fileOperator.SetFileCompletedLength(position); + while (true) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel("主动取消"); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + int r = reader.Read(byteBlock.Buffer, 0, + (int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0)); + if (r == 0) + { + channel.Complete(); + break; + } + else + { + position += r; + if (channel.TryWrite(byteBlock.Buffer, 0, r)) + { + fileOperator.AddFlow(r); + } + else + { + break; + } + } + } + } + catch + { + } + finally + { + byteBlock.Dispose(); + + e = new FileTransferStatusEventArgs( + fileOperator.SetResult(new Result(channel.Status.ToResultCode())), args); + OnFileTransfered?.Invoke(this, e); + } + + return; + } + else + { + waitTransferPackage.Status = TouchSocketStatus.SetChannelFail.ToValue(); + e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.SetChannelFail)), args); + } + } + } + catch (Exception ex) + { + waitTransferPackage.Status = TouchSocketStatus.Exception.ToValue(); + waitTransferPackage.Message = ex.Message; + e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.LoadStreamFail)), args); + } + } + else + { + e = new FileTransferStatusEventArgs(TransferType.Pull, default, default, new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.GetEventArgsFail))); + waitTransferPackage.Status = TouchSocketStatus.GetEventArgsFail.ToValue(); + } + + waitTransferPackage.SwitchId(); + SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage); + + OnFileTransfered?.Invoke(this, e); + } + catch + { + } + } + + private void RequestPullFile(object o) + { + try + { + WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o; + try + { + FileOperator fileOperator = new FileOperator() + { + Flags = waitFileInfoPackage.Flags, + ResourcePath = waitFileInfoPackage.ResourcePath, + SavePath = waitFileInfoPackage.SavePath, + Metadata = waitFileInfoPackage.Metadata + }; + + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Pull, + fileOperator, null); + + OnFileTransfering?.Invoke(this, args); + + args.ResourcePath = FileController.GetFullPath(m_rootPath, args.ResourcePath); + + if (args.IsPermitOperation) + { + if (File.Exists(args.ResourcePath)) + { + //合法传输 + TouchRpcFileInfo touchRpcFileInfo = new TouchRpcFileInfo(); + FileController.GetFileInfo(args.ResourcePath, args.Flags.HasFlag(TransferFlags.MD5Verify), ref touchRpcFileInfo); + waitFileInfoPackage.FileInfo = touchRpcFileInfo; + waitFileInfoPackage.Status = TouchSocketStatus.Success.ToValue(); + waitFileInfoPackage.EventHashCode = args.GetHashCode(); + if (m_eventArgs.TryAdd(args.GetHashCode(), args)) + { + EasyTask.DelayRun(1000 * 60, args, (a) => + { + if (m_eventArgs.TryRemove(a.GetHashCode(), out object obj) && obj is FileOperationEventArgs eventArgs) + { + FileTransferStatusEventArgs e = new FileTransferStatusEventArgs( + new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.Overtime)), eventArgs); + OnFileTransfered?.Invoke(this, e); + } + }); + } + else + { + waitFileInfoPackage.Status = TouchSocketStatus.UnknownError.ToValue(); + } + } + else + { + waitFileInfoPackage.Status = TouchSocketStatus.FileNotExists.ToValue(); + } + } + else + { + waitFileInfoPackage.Message = args.Message; + waitFileInfoPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + } + } + catch (Exception ex) + { + waitFileInfoPackage.Status = TouchSocketStatus.Exception.ToValue(); + waitFileInfoPackage.Message = ex.Message; + } + waitFileInfoPackage.SwitchId(); + this.SendPackage(TouchRpcUtility.P_1500_PullFile_Response, waitFileInfoPackage); + } + catch + { + } + } + + private void RequestPushFile(object o) + { + try + { + WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o; + TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo; + FileOperator fileOperator = new FileOperator() + { + ResourcePath = waitFileInfoPackage.ResourcePath, + SavePath = waitFileInfoPackage.SavePath, + Flags = waitFileInfoPackage.Flags, + Metadata = waitFileInfoPackage.Metadata, + }; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage() + { + Sign = waitFileInfoPackage.Sign, + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + }; + + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Push, fileOperator, fileInfo); + OnFileTransfering?.Invoke(this, args); + + waitTransferPackage.Path = args.ResourcePath; + waitTransferPackage.EventHashCode = args.GetHashCode(); + + if (!args.IsPermitOperation) + { + fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message))); + waitTransferPackage.Message = args.Message; + waitTransferPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + return; + } + + string saveFullPath = FileController.GetFullPath(m_rootPath, args.SavePath); + + if (!Directory.Exists(Path.GetDirectoryName(saveFullPath))) + { + fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.DirectoryNotExists.GetDescription(Path.GetDirectoryName(saveFullPath)))); + waitTransferPackage.Message = args.Message; + waitTransferPackage.Status = TouchSocketStatus.DirectoryNotExists.ToValue(); + waitTransferPackage.Path = Path.GetDirectoryName(saveFullPath); + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + return; + } + Channel channel = null; + try + { + FileController.TryReadTempInfo(saveFullPath, args.Flags, ref fileInfo); + using (TouchRpcFileStream stream = TouchRpcFileStream.Create(saveFullPath, ref fileInfo, args.Flags.HasFlag(TransferFlags.MD5Verify))) + { + if (waitFileInfoPackage.Route) + { + channel = CreateChannel(waitTransferPackage.SourceId); + } + else + { + channel = CreateChannel(); + } + + waitTransferPackage.ChannelID = channel.ID; + waitTransferPackage.Position = fileInfo.Position; + waitTransferPackage.Status = TouchSocketStatus.Success.ToValue(); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + + fileOperator.SetFileCompletedLength(fileInfo.Position); + fileOperator.SetLength(fileInfo.Length); + while (channel.MoveNext()) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + + byte[] data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + fileInfo.Position = stream.FileWriter.Position; + fileOperator.AddFlow(data.Length); + } + } + + if (channel.Status == ChannelStatus.Completed) + { + stream.FinishStream(); + fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + } + catch (Exception ex) + { + fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + channel?.Cancel(ex.Message); + } + finally + { + channel.SafeDispose(); + } + + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + if (channel?.Status == ChannelStatus.Completed && fileOperator.Result.IsSuccess()) + { + SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage() + { + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + Sign = args.GetHashCode(), + Status = TouchSocketStatus.Success.ToValue(), + Message = fileOperator.Result.Message + }); + } + else + { + SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage() + { + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + Sign = args.GetHashCode(), + Status = TouchSocketStatus.Exception.ToValue(), + Message = fileOperator.Result.Message + }); + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs.meta new file mode 100644 index 0000000..4f4ebd5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6ee5cf183d2e6a488f7916be5889255 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs new file mode 100644 index 0000000..e7a0390 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs @@ -0,0 +1,1085 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_contextDic; + + /// + public object Caller { get; set; } + + /// + public RpcStore RpcStore { get; set; } + + /// + public SerializationSelector SerializationSelector { get; set; } + + #region Rpc + + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + catch (System.Exception e) + { + throw new Exception(e.Message); + } + } + else + { + parameters = null; + } + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + break; + + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(invokeKey, invokeOption, parameters); + }); + } + + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(invokeKey, invokeOption, parameters); + }); + } + + #endregion Rpc + + #region IdRpc + + /// + public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + actor.Invoke(invokeKey, invokeOption, parameters); + return; + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + Route = true, + TargetId = targetId, + SourceId = ID, + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + break; + + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Invoke(invokeKey, invokeOption, parameters); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + rpcActor.Invoke(invokeKey, invokeOption, ref parameters, types); + return; + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return; + } + + default: + return; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Invoke(invokeKey, invokeOption, ref parameters, types); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public Task InvokeAsync(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(targetId, invokeKey, invokeOption, parameters); + }); + } + + /// + public Task InvokeAsync(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(targetId, invokeKey, invokeOption, parameters); + }); + } + + #endregion IdRpc + + private void CanceledInvoke(object obj) + { + if (obj is CanceledPackage canceled) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + canceled.Package(byteBlock); + Send(TouchRpcUtility.P_204_CancelInvoke, byteBlock); + } + } + } + + private void InvokeThis(object o) + { + try + { + TouchRpcPackage rpcPackage = (TouchRpcPackage)o; + + List psData = rpcPackage.ParametersBytes; + if (rpcPackage.Feedback == FeedbackType.WaitSend) + { + using (ByteBlock returnByteBlock = new ByteBlock()) + { + var methodName = rpcPackage.MethodName; + var parametersBytes = rpcPackage.ParametersBytes; + + rpcPackage.SwitchId(); + rpcPackage.MethodName = default; + rpcPackage.ParametersBytes = default; + rpcPackage.Status = TouchSocketStatus.Success.ToValue(); + rpcPackage.Package(returnByteBlock); + Send(TouchRpcUtility.P_1200_Invoke_Response, returnByteBlock); + + rpcPackage.SwitchId(); + rpcPackage.MethodName= methodName; + rpcPackage.ParametersBytes = parametersBytes; + } + } + + InvokeResult invokeResult = new InvokeResult(); + object[] ps = null; + MethodInstance methodInstance = GetInvokeMethod?.Invoke(rpcPackage.MethodName); + TouchRpcCallContext callContext = null; + if (methodInstance != null) + { + try + { + if (methodInstance.IsEnable) + { + callContext = new TouchRpcCallContext() + { + Caller = Caller, + MethodInstance = methodInstance, + TouchRpcPackage = rpcPackage + }; + + m_contextDic.TryAdd(rpcPackage.Sign, callContext); + + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps = new object[methodInstance.ParameterTypes.Length]; + ps[0] = callContext; + for (int i = 0; i < psData.Count; i++) + { + ps[i + 1] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i + 1]); + } + } + else + { + ps = new object[methodInstance.ParameterTypes.Length]; + for (int i = 0; i < methodInstance.ParameterTypes.Length; i++) + { + ps[i] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i]); + } + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = RpcStore.Execute(rpcServer, ps, callContext); + } + + if (rpcPackage.Feedback == FeedbackType.OnlySend) + { + return; + } + + switch (invokeResult.Status) + { + case InvokeStatus.UnFound: + { + rpcPackage.Status = TouchSocketStatus.RpcMethodNotFind.ToValue(); + break; + } + case InvokeStatus.Success: + { + if (methodInstance.HasReturn) + { + rpcPackage.ReturnParameterBytes = SerializationSelector.SerializeParameter(rpcPackage.SerializationType, invokeResult.Result); + } + else + { + rpcPackage.ReturnParameterBytes = null; + } + + if (methodInstance.IsByRef) + { + rpcPackage.IsByRef = true; + rpcPackage.ParametersBytes = new List(); + + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + for (; i < ps.Length; i++) + { + rpcPackage.ParametersBytes.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, ps[i])); + } + } + else + { + rpcPackage.ParametersBytes = null; + } + + rpcPackage.Status = TouchSocketStatus.Success.ToValue(); + break; + } + case InvokeStatus.UnEnable: + { + rpcPackage.Status = TouchSocketStatus.RpcMethodDisable.ToValue(); + break; + } + case InvokeStatus.InvocationException: + { + rpcPackage.Status = TouchSocketStatus.RpcInvokeException.ToValue(); + rpcPackage.Message = invokeResult.Message; + break; + } + case InvokeStatus.Exception: + { + rpcPackage.Status = TouchSocketStatus.Exception.ToValue(); + rpcPackage.Message = invokeResult.Message; + break; + } + default: + return; + } + + m_contextDic.TryRemove(rpcPackage.Sign, out _); + + using (ByteBlock byteBlock = new ByteBlock()) + { + rpcPackage.MethodName = default; + rpcPackage.SwitchId(); + rpcPackage.Package(byteBlock); + Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock); + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs.meta new file mode 100644 index 0000000..6656ed0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b204a2155cd08d4f97c2e320feab1fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs new file mode 100644 index 0000000..e1ee902 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs @@ -0,0 +1,295 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + /// + /// 发送流数据 + /// + /// + /// + /// + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = default) + { + WaitStream waitStream = new WaitStream(); + WaitData waitData = WaitHandlePool.GetWaitData(waitStream); + waitStream.Metadata = metadata; + long size = stream.Length - stream.Position; + streamOperator.SetLength(size); + waitStream.Size = size; + waitStream.StreamType = stream.GetType().FullName; + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + byteBlock.WriteObject(waitStream); + try + { + Send(TouchRpcUtility.P_400_SendStreamToSocketClient_Request, byteBlock); + + waitData.SetCancellationToken(streamOperator.Token); + + waitData.Wait(streamOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitStream waitStreamResult = (WaitStream)waitData.WaitResult; + if (waitStreamResult.Status == 1) + { + if (TrySubscribeChannel(waitStreamResult.ChannelID, out Channel channel)) + { + while (true) + { + if (streamOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + return streamOperator.SetResult(new Result(ResultCode.Canceled)); + } + int r = stream.Read(byteBlock.Buffer, 0, + (int)Math.Min(TouchRpcUtility.TransferPackage, streamOperator.MaxSpeed / 10.0)); + if (r <= 0) + { + channel.Complete(); + return streamOperator.SetResult(new Result(ResultCode.Success)); + } + + channel.Write(byteBlock.Buffer, 0, r); + streamOperator.AddFlow(r); + } + } + else + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.SetChannelFail.GetDescription())); + } + } + else if (waitStreamResult.Status == 2) + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStreamResult.Message))); + } + else if (waitStreamResult.Status == 3) + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.Exception.GetDescription(waitStreamResult.Message))); + } + else + { + return streamOperator.SetResult(new Result(ResultCode.Error)); + } + } + case WaitDataStatus.Overtime: + { + return streamOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return streamOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return streamOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + /// 发送流数据 + /// + /// + /// + /// + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = default) + { + return EasyTask.Run(() => + { + return SendStream(stream, streamOperator, metadata); + }); + } + + private void RequestStreamToClient(object obj) + { + try + { + WaitStream waitStream = (WaitStream)obj; + StreamOperator streamOperator = new StreamOperator(); + StreamInfo streamInfo = new StreamInfo(waitStream.Size, waitStream.StreamType); + StreamOperationEventArgs args = new StreamOperationEventArgs(streamOperator, waitStream.Metadata, streamInfo); + + try + { + OnStreamTransfering?.Invoke(this, args); + + if (args.IsPermitOperation) + { + if (args.Bucket != null) + { + waitStream.Status = 1; + Channel channel = CreateChannel(); + waitStream.ChannelID = channel.ID; + TaskTransferingStream(streamOperator, args, channel, waitStream.Size); + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.StreamBucketNull.GetDescription())); + waitStream.Status = 3; + waitStream.Message = "未设置流容器"; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, waitStream.Message), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, args.Message)); + waitStream.Status = 2; + waitStream.Message = args.Message; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStream.Message)), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + catch (Exception ex) + { + streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + waitStream.Status = 3; + waitStream.Message = ex.Message; + + Logger.Log(LogType.Error, this, $"在{nameof(RequestStreamToClient)}中发生错误。", ex); + } + + waitStream.Metadata = null; + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.WriteObject(waitStream); + Send(TouchRpcUtility.P_401_SendStreamToClient, byteBlock); + } + } + catch + { + } + } + + private void RequestStreamToSocketClient(object obj) + { + try + { + WaitStream waitStream = (WaitStream)obj; + StreamOperator streamOperator = new StreamOperator(); + StreamInfo streamInfo = new StreamInfo(waitStream.Size, waitStream.StreamType); + StreamOperationEventArgs args = new StreamOperationEventArgs(streamOperator, waitStream.Metadata, streamInfo); + + try + { + OnStreamTransfering?.Invoke(this, args); + if (args.IsPermitOperation) + { + if (args.Bucket != null) + { + waitStream.Status = 1; + Channel channel = CreateChannel(); + waitStream.ChannelID = channel.ID; + TaskTransferingStream(streamOperator, args, channel, waitStream.Size); + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.StreamBucketNull.GetDescription())); + waitStream.Status = 3; + waitStream.Message = "未设置流容器"; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, waitStream.Message), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, args.Message)); + waitStream.Status = 2; + waitStream.Message = args.Message; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStream.Message)), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + catch (Exception ex) + { + streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + waitStream.Status = 3; + waitStream.Message = ex.Message; + + Logger.Log(LogType.Error, this, $"在{nameof(RequestStreamToSocketClient)}中发生错误。", ex); + } + + waitStream.Metadata = null; + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.WriteObject(waitStream); + Send(TouchRpcUtility.P_1400_SendStreamToSocketClient_Response, byteBlock); + } + } + catch + { + } + } + + private void TaskTransferingStream(StreamOperator streamOperator, StreamOperationEventArgs args, Channel channel, long size) + { + ThreadPool.QueueUserWorkItem((obj) => + { + try + { + streamOperator.SetLength(size); + Stream stream = args.Bucket; + while (channel.MoveNext()) + { + if (streamOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + streamOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + var data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + streamOperator.AddFlow(data.Length); + } + } + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(streamOperator.SetResult(new Result(channel.Status.ToResultCode())), + args.Metadata, args.StreamInfo) + { Bucket = stream, Message = args.Message }); + } + catch + { + } + }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs.meta new file mode 100644 index 0000000..7588671 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e596f18b962eb44cb5f4a163182d355 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs new file mode 100644 index 0000000..de3997e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs @@ -0,0 +1,1387 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActor + /// + public partial class RpcActor : DisposableObject, IRpcActor + { + /// + /// 结束标识编码。 + /// + public static readonly byte[] EndCodes = new byte[] { 20, 17, 11, 25 }; + + #region 委托 + + /// + /// 获取调用函数的委托 + /// + public Func GetInvokeMethod { get; set; } + + /// + /// 请求关闭 + /// + public Action OnClose { get; set; } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + public Action OnFileTransfered { get; set; } + + /// + /// 当需要路由的时候 + /// + public Action OnRouting { get; set; } + + /// + /// 在文件传输即将进行时触发。 + /// + public Action OnFileTransfering { get; set; } + + /// + /// 查找其他RpcActor + /// + public Func OnFindRpcActor { get; set; } + + /// + /// 在完成握手连接时 + /// + public Action OnHandshaked { get; set; } + + /// + /// 握手 + /// + public Action OnHandshaking { get; set; } + + /// + /// 接收到数据 + /// + public Action OnReceived { get; set; } + + /// + /// 重设ID + /// + public Action OnResetID { get; set; } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + public Action OnStreamTransfered { get; set; } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + public Action OnStreamTransfering { get; set; } + + /// + /// 发送数据接口 + /// + public Action[]> OutputSend { get; set; } + + #endregion 委托 + + #region 属性 + + /// + /// 文件资源访问接口。 + /// + public IFileResourceController FileController { get; set; } + + /// + /// 本节点ID + /// + public string ID { get; set; } + + /// + /// + /// + public bool IsHandshaked { get; private set; } + + /// + /// 是否为服务器组件 + /// + public bool IsService { get; private set; } + + /// + /// 日志 + /// + public ILog Logger { get; set; } + + /// + /// 获取可用于同步对的访问的对象。 + /// + public object SyncRoot { get; } = new object(); + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// 等待返回池 + /// + public WaitHandlePool WaitHandlePool { get; private set; } + + #endregion 属性 + + /// + /// 构造函数 + /// + public RpcActor(bool isService) + { + m_eventArgs = new ConcurrentDictionary(); + WaitHandlePool = new WaitHandlePool(); + m_userChannels = new ConcurrentDictionary(); + m_contextDic = new ConcurrentDictionary(); + IsService = isService; + } + + /// + /// 关闭 + /// + /// + public void Close(string message) + { + if (IsHandshaked) + { + IsHandshaked = false; + foreach (var item in m_userChannels.Values) + { + item.RequestDispose(false); + } + var keys = m_contextDic.Keys.ToArray(); + foreach (var item in keys) + { + if (m_contextDic.TryRemove(item, out TouchRpcCallContext rpcCallContext)) + { + rpcCallContext.TryCancel(); + } + } + WaitHandlePool.CancelAll(); + OnClose?.Invoke(this, message); + } + } + + /// + /// 建立对点 + /// + /// + /// + /// + public void Handshake(string verifyToken, string id, CancellationToken token = default, int timeout = 5000, Metadata metadata = null) + { + if (IsHandshaked) + { + return; + } + WaitVerify waitVerify = new WaitVerify() + { + Token = verifyToken, + ID = id, + Metadata = metadata + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitVerify); + waitData.SetCancellationToken(token); + + try + { + SendFastObject(TouchRpcUtility.P_0_Handshake_Request, waitVerify); + switch (waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + { + WaitVerify verifyResult = (WaitVerify)waitData.WaitResult; + if (verifyResult.Status == 1) + { + ID = verifyResult.ID; + IsHandshaked = true; + OnHandshaked?.Invoke(this, new VerifyOptionEventArgs(verifyToken, verifyResult.Metadata) { Message = "成功建立" }); + verifyResult.Handle = true; + return; + } + else if (verifyResult.Status == 3) + { + verifyResult.Handle = true; + Close("连接数量已达到服务器设定最大值"); + throw new Exception("连接数量已达到服务器设定最大值"); + } + else if (verifyResult.Status == 4) + { + verifyResult.Handle = true; + Close("服务器拒绝连接"); + throw new Exception("服务器拒绝连接"); + } + else + { + verifyResult.Handle = true; + Close(verifyResult.Message); + throw new TokenVerifyException(verifyResult.Message); + } + } + case WaitDataStatus.Overtime: + Close("连接超时"); + throw new TimeoutException("连接超时"); + case WaitDataStatus.Canceled: + case WaitDataStatus.Disposed: + default: + Close(null); + return; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + } + } + + /// + /// 处理接收数据 + /// + /// + public void InputReceivedData(ByteBlock byteBlock) + { + short protocol = TouchSocketBitConverter.Default.ToInt16(byteBlock.Buffer, 0); + switch (protocol) + { + #region 0-99 + + case TouchRpcUtility.P_0_Handshake_Request: + { + try + { + WaitVerify waitVerify = byteBlock.Seek(2).ReadObject(); + VerifyOptionEventArgs args = new VerifyOptionEventArgs(waitVerify.Token, waitVerify.Metadata); + if (!waitVerify.ID.IsNullOrEmpty()) + { + OnResetID?.Invoke(true, this, new WaitSetID(ID, waitVerify.ID)); + ID = waitVerify.ID; + } + OnHandshaking?.Invoke(this, args); + + if (args.IsPermitOperation) + { + waitVerify.ID = ID; + waitVerify.Status = 1; + byteBlock.Reset(); + byteBlock.WriteObject(waitVerify); + Send(TouchRpcUtility.P_1000_Handshake_Response, byteBlock); + IsHandshaked = true; + args.Message = "Success"; + ThreadPool.QueueUserWorkItem((o) => + { + try + { + OnHandshaked?.Invoke(this, args); + } + catch + { + } + },default); + } + else + { + waitVerify.Status = 2; + waitVerify.Message = args.Message; + byteBlock.Reset(); + byteBlock.WriteObject(waitVerify); + Send(TouchRpcUtility.P_1000_Handshake_Response, byteBlock); + Close(args.Message); + } + } + catch (Exception ex) + { + Close(ex.Message); + } + return; + } + case TouchRpcUtility.P_1000_Handshake_Response: + { + WaitVerify waitVerify = byteBlock.Seek(2).ReadObject(); + WaitHandlePool.SetRun(waitVerify); + SpinWait.SpinUntil(() => + { + return waitVerify.Handle; + }, 3000); + return; + } + case TouchRpcUtility.P_1_ResetID_Request: + { + try + { + byteBlock.Pos = 2; + WaitSetID waitSetID = byteBlock.ReadObject(); + try + { + OnResetID?.Invoke(false, this, waitSetID); + ID = waitSetID.NewID; + waitSetID.Status = 1; + } + catch (System.Exception ex) + { + waitSetID.Status = 2; + waitSetID.Message = ex.Message; + } + byteBlock.Reset(); + byteBlock.WriteObject(waitSetID); + Send(TouchRpcUtility.P_1001_ResetID_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1001_ResetID_Response: + { + try + { + byteBlock.Pos = 2; + WaitHandlePool.SetRun(byteBlock.ReadObject()); + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_2_Ping_Request://心跳 + { + byteBlock.Pos = 2; + + try + { + WaitPingPackage waitPing = new WaitPingPackage(); + waitPing.UnpackageRouter(byteBlock); + if (IsService && waitPing.Route) + { + if (TryRoute(RouteType.Ping, waitPing)) + { + if (TryFindRpcActor(waitPing.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_2_Ping_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.Success.ToValue(); + } + waitPing.SwitchId(); + byteBlock.Reset(); + waitPing.Package(byteBlock); + Send(TouchRpcUtility.P_1002_Ping_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1002_Ping_Response://心跳 + { + try + { + byteBlock.Pos = 2; + WaitPingPackage waitPing = new WaitPingPackage(); + waitPing.UnpackageRouter(byteBlock); + if (IsService && waitPing.Route) + { + if (TryFindRpcActor(waitPing.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1002_Ping_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitPing); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 0-99 + + #region 100-199 + + case TouchRpcUtility.P_100_CreateChannel_Request: + { + try + { + byteBlock.Pos = 2; + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage(); + waitCreateChannel.UnpackageRouter(byteBlock); + if (this.IsService && waitCreateChannel.Route) + { + if (this.TryRoute(RouteType.CreateChannel, waitCreateChannel)) + { + if (TryFindRpcActor(waitCreateChannel.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_100_CreateChannel_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + waitCreateChannel.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + waitCreateChannel.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + + while (true) + { + if (RequestCreateChannel(waitCreateChannel.ChannelID, waitCreateChannel.Route ? waitCreateChannel.SourceId : waitCreateChannel.TargetId)) + { + waitCreateChannel.Status = TouchSocketStatus.Success.ToValue(); + break; + } + else + { + waitCreateChannel.Status = TouchSocketStatus.ChannelExisted.ToValue(); + } + + if (!waitCreateChannel.Random) + { + break; + } + waitCreateChannel.ChannelID = new object().GetHashCode(); + } + } + + waitCreateChannel.SwitchId(); + byteBlock.Reset(); + waitCreateChannel.Package(byteBlock); + Send(TouchRpcUtility.P_1100_CreateChannel_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1100_CreateChannel_Response: + { + try + { + byteBlock.Pos = 2; + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage(); + waitCreateChannel.UnpackageRouter(byteBlock); + if (this.IsService && waitCreateChannel.Route) + { + if (TryFindRpcActor(waitCreateChannel.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1100_CreateChannel_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitCreateChannel); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_101_ChannelPackage: + { + try + { + byteBlock.Pos = 2; + ChannelPackage channelPackage = new ChannelPackage(); + channelPackage.UnpackageRouter(byteBlock); + if (this.IsService && channelPackage.Route) + { + if (TryFindRpcActor(channelPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + else + { + channelPackage.UnpackageBody(byteBlock); + channelPackage.Message = TouchSocketStatus.ClientNotFind.GetDescription(channelPackage.TargetId); + channelPackage.SwitchId(); + channelPackage.RunNow = true; + channelPackage.DataType = ChannelDataType.DisposeOrder; + byteBlock.Reset(); + channelPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock); + } + } + else + { + channelPackage.UnpackageBody(byteBlock); + QueueChannelPackage(channelPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 100-199 + + #region 200-299 + + case TouchRpcUtility.P_200_Invoke_Request: + { + try + { + byteBlock.Pos = 2; + WaitRouterPackage waitRouterPackage = new WaitRouterPackage(); + waitRouterPackage.UnpackageRouter(byteBlock); + if (IsService && waitRouterPackage.Route) + { + if (this.TryRoute(RouteType.Rpc, waitRouterPackage)) + { + if (TryFindRpcActor(waitRouterPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitRouterPackage.UnpackageBody(byteBlock); + waitRouterPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitRouterPackage.UnpackageBody(byteBlock); + waitRouterPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitRouterPackage.SwitchId(); + + TouchRpcPackage rpcPackage = waitRouterPackage.Map(); + rpcPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock); + } + else + { + TouchRpcPackage rpcPackage = new TouchRpcPackage(); + rpcPackage.Unpackage(byteBlock.Seek(2)); + ThreadPool.QueueUserWorkItem(InvokeThis, rpcPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1200_Invoke_Response: + { + try + { + byteBlock.Pos = 2; + TouchRpcPackage rpcPackage = new TouchRpcPackage(); + rpcPackage.UnpackageRouter(byteBlock); + if (IsService && rpcPackage.Route) + { + if (this.TryFindRpcActor(rpcPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + rpcPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(rpcPackage); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_204_CancelInvoke: + { + try + { + byteBlock.Pos = 2; + CanceledPackage canceledPackage = new CanceledPackage(); + canceledPackage.UnpackageRouter(byteBlock); + if (IsService && canceledPackage.Route) + { + if (this.TryFindRpcActor(canceledPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_204_CancelInvoke, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + canceledPackage.UnpackageBody(byteBlock); + if (m_contextDic.TryGetValue(canceledPackage.Sign, out TouchRpcCallContext context)) + { + context.TokenSource.Cancel(); + } + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 200-299 + + #region 400-499 + + case TouchRpcUtility.P_400_SendStreamToSocketClient_Request://StreamStatusToThis + { + try + { + byteBlock.Pos = 2; + ThreadPool.QueueUserWorkItem(RequestStreamToSocketClient, byteBlock.ReadObject()); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1400_SendStreamToSocketClient_Response://StreamStatusToThis + { + try + { + byteBlock.Pos = 2; + WaitStream waitStream = byteBlock.ReadObject(); + WaitHandlePool.SetRun(waitStream); + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_401_SendStreamToClient://StreamToThis + { + try + { + byteBlock.Pos = 2; + ThreadPool.QueueUserWorkItem(RequestStreamToClient, byteBlock.ReadObject()); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 400-499 + + #region 500-599 + + case TouchRpcUtility.P_500_PullFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitFileInfoPackage)) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_500_PullFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitFileInfoPackage.SwitchId(); + waitFileInfoPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1500_PullFile_Response, byteBlock); + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPullFile, waitFileInfoPackage); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1500_PullFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1500_PullFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitFileInfoPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + + return; + } + case TouchRpcUtility.P_501_BeginPullFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_501_BeginPullFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + waitTransferPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + byteBlock.Reset(); + waitTransferPackage.SwitchId(); + waitTransferPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1501_BeginPullFile_Response, byteBlock); + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(BeginPullFile, waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1501_BeginPullFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1501_BeginPullFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_502_PushFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitFileInfoPackage)) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_502_PushFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitFileInfoPackage.SwitchId(); + waitFileInfoPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1502_PushFile_Response, byteBlock); + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPushFile, waitFileInfoPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1502_PushFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1502_PushFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + + return; + } + case TouchRpcUtility.P_509_PushFileAck_Request: + { + try + { + byteBlock.Pos = 2; + WaitPushFileAckPackage waitPushFileAckPackage = new WaitPushFileAckPackage(); + waitPushFileAckPackage.UnpackageRouter(byteBlock); + if (IsService && waitPushFileAckPackage.Route) + { + if (TryFindRpcActor(waitPushFileAckPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_509_PushFileAck_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitPushFileAckPackage.UnpackageBody(byteBlock); + m_eventArgs.TryAdd((int)waitPushFileAckPackage.Sign, waitPushFileAckPackage); + + EasyTask.DelayRun(10000, waitPushFileAckPackage, (a) => + { + m_eventArgs.TryRemove((int)((WaitPushFileAckPackage)a).Sign, out _); + }); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_517_PullSmallFile_Request: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitSmallFilePackage)) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + byteBlock.Reset(); + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1517_PullSmallFile_Response, byteBlock); + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPullSmallFile, waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1517_PullSmallFile_Response: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_518_PushSmallFile_Request: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitSmallFilePackage)) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + byteBlock.Reset(); + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock); + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPushSmallFile, waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1518_PushSmallFile_Response: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 500-599 + + default: + { + try + { + OnReceived?.Invoke(this, protocol, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + break; + } + } + } + + /// + /// 尝试获取指定Id的RpcActor。一般此方法仅在Service下有效。 + /// + /// + /// + /// + public bool TryFindRpcActor(string targetId, out RpcActor rpcActor) + { + if (targetId == ID) + { + rpcActor = this; + return true; + } + if (OnFindRpcActor?.Invoke(targetId) is RpcActor actor) + { + rpcActor = actor; + return true; + } + + rpcActor = default; + return false; + } + + /// + /// 尝试请求路由,触发路由相关插件。 + /// + /// + /// + /// + public bool TryRoute(RouteType routerType, RouterPackage routerPackage) + { + try + { + PackageRouterEventArgs args = new PackageRouterEventArgs(routerType, routerPackage); + OnRouting?.Invoke(this, args); + return args.IsPermitOperation; + } + catch + { + return false; + } + } + + /// + /// 尝试请求路由,触发路由相关插件。并在路由失败时向中传递消息。 + /// + /// + /// + /// + public bool TryRoute(RouteType routerType, WaitRouterPackage routerPackage) + { + try + { + PackageRouterEventArgs args = new PackageRouterEventArgs(routerType, routerPackage); + OnRouting?.Invoke(this, args); + routerPackage.Message = args.Message; + return args.IsPermitOperation; + } + catch + { + return false; + } + } + + /// + public bool Ping(int timeout = 5000) + { + return PrivatePing(default, timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Ping(timeout); + } + return false; + } + return PrivatePing(targetId, timeout); + } + + private bool PrivatePing(string targetId, int timeout) + { + try + { + WaitPingPackage waitPing = new WaitPingPackage + { + TargetId = targetId, + SourceId = ID, + Route = targetId.HasValue() + }; + var wait = WaitHandlePool.GetWaitData(waitPing); + using (ByteBlock byteBlock = new ByteBlock()) + { + waitPing.Package(byteBlock); + Send(TouchRpcUtility.P_2_Ping_Request, byteBlock); + } + + switch (wait.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + { + switch (wait.WaitResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: return true; + default: + return false; + } + } + case WaitDataStatus.Default: + case WaitDataStatus.Overtime: + case WaitDataStatus.Canceled: + case WaitDataStatus.Disposed: + default: + return false; + } + } + catch + { + return false; + } + } + + /// + /// 重新设置ID,并且同步到对端 + /// + /// + /// + public void ResetID(string id) + { + WaitSetID waitSetID = new WaitSetID(ID, id); + + WaitData waitData = WaitHandlePool.GetWaitData(waitSetID); + + ByteBlock byteBlock = new ByteBlock(); + byteBlock.WriteObject(waitSetID); + + Send(TouchRpcUtility.P_1_ResetID_Request, byteBlock.Buffer, 0, byteBlock.Len); + + switch (waitData.Wait(5000)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + ID = id; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + break; + } + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + break; + + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + + /// + /// 以Fast序列化,发送小(64K)对象。接收方需要将Pos设为2,然后ReadObject即可。 + /// + /// + /// + public void SendFastObject(short protocol, object obj) + { + using ByteBlock byteBlock = new ByteBlock(); + byteBlock.WriteObject(obj, SerializationType.FastBinary); + Send(protocol, byteBlock); + } + + /// + /// 以包发送小(64K)对象。接收方需要将Pos设为2,然后ReadPackage即可。 + /// + /// + /// + public void SendPackage(short protocol, IPackage package) + { + using ByteBlock byteBlock = new ByteBlock(); + package.Package(byteBlock); + Send(protocol, byteBlock); + } + + #region 重写 + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + Caller = null; + OnClose = null; + OnFileTransfered = null; + OnFileTransfering = null; + OnRouting = null; + OnFindRpcActor = null; + OnHandshaked = null; + OnHandshaking = null; + OnReceived = null; + OnResetID = null; + OnStreamTransfered = null; + OnStreamTransfering = null; + OutputSend = null; + WaitHandlePool.SafeDispose(); + Close(nameof(Dispose)); + base.Dispose(disposing); + } + + #endregion 重写 + + #region 协议同步发送 + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + ArraySegment[] transferBytes = new ArraySegment[] + { + new ArraySegment(TouchSocketBitConverter.Default.GetBytes(protocol)), + new ArraySegment(buffer,offset,length) + }; + OutputSend?.Invoke(this, transferBytes); + } + + private void Send(short protocol, ByteBlock byteBlock) + { + Send(protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + #endregion 协议同步发送 + + #region 协议异步发送 + + /// + /// 异步发送字节 + /// + /// + /// + /// + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(protocol, buffer, offset, length); + }); + } + + #endregion 协议异步发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs.meta new file mode 100644 index 0000000..1a716f4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a661cc986fb331478ef2db0e3de2d83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp.meta new file mode 100644 index 0000000..a72f5d3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba51d605b51ff0e468f235a1b0c7fe33 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs new file mode 100644 index 0000000..5573f96 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class UdpRpcActor : RpcActor + { + private readonly UdpSessionBase m_udpSession; + private readonly EndPoint m_endPoint; + + public int Tick; + + public UdpRpcActor(UdpSessionBase udpSession, EndPoint endPoint, ILog logger) : base(false) + { + OutputSend = RpcActorSend; + m_udpSession = udpSession; + m_endPoint = endPoint; + Logger = logger; + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + m_udpSession.Send(m_endPoint, transferBytes); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs.meta new file mode 100644 index 0000000..35ec09b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef3bff88e983bc64499817ea68adbc36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream.meta new file mode 100644 index 0000000..c9d3aa1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 001ef8adbc4815d4bbb5d1e4e37334f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs new file mode 100644 index 0000000..bb2504c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流信息 + /// + public struct StreamInfo + { + /// + /// 构造函数 + /// + /// + /// + public StreamInfo(long size, string streamType) + { + Size = size; + StreamType = streamType; + } + + /// + /// 流长度 + /// + public long Size { get; private set; } + + /// + /// 流类型 + /// + public string StreamType { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs.meta new file mode 100644 index 0000000..95ce1f6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ae89b49a2db0e641b5596b7bf3675ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs new file mode 100644 index 0000000..f9c431a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流传输操作器 + /// + public class StreamOperator : FlowOperator + { + + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs.meta new file mode 100644 index 0000000..5231634 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3580698f1fee1514d935168e6cfaa6b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs new file mode 100644 index 0000000..1a5dd62 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 等待流状态返回 + /// + public class WaitStream : WaitResult + { + /// + /// 流长度 + /// + public long Size { get; set; } + + /// + /// 流类型 + /// + public string StreamType { get; set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 开启的通道标识 + /// + public int ChannelID { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs.meta new file mode 100644 index 0000000..3d51ca1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8a3931284efbca4c81d405d5ab30525 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi.meta new file mode 100644 index 0000000..484bdba --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56ce8046452d16e438924528818d5d8b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute.meta new file mode 100644 index 0000000..a02e87e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0fa35b05122a14f4ba70bd5dc4ac9cf3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs new file mode 100644 index 0000000..d3dbe11 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 跨域相关设置 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class OriginAttribute : RpcActionFilterAttribute + { + /// + /// 允许客户端携带验证信息 + /// + public bool AllowCredentials { get; set; } = true; + + /// + /// 允许跨域的方法。 + /// 默认为“PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH” + /// + public string AllowMethods { get; set; } = "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH"; + + /// + /// 允许跨域的域名 + /// + public string AllowOrigin { get; set; } = "*"; + + /// + /// + /// + /// + /// + /// + public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + if (callContext is IHttpCallContext httpCallContext && httpCallContext.HttpContext != default) + { + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Origin", AllowOrigin); + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Methods", AllowMethods); + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Credentials", AllowCredentials.ToString().ToLower()); + } + base.Executed(callContext,parameters, ref invokeResult); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs.meta new file mode 100644 index 0000000..db8e41b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b962b422e9635464a8d5c3796de9e9b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs new file mode 100644 index 0000000..998841c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 表示WebApi路由。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class RouterAttribute : Attribute + { + /// + /// 表示WebApi路由。 + /// 该模板在用于方法时,会覆盖类的使用。 + /// 模板必须由“/”开始,如果没有设置,会自动补齐。 + /// 模板不支持参数约定,仅支持方法路由。 + /// 模板有以下约定: + /// + /// 不区分大小写 + /// 以“[Api]”表示当前类名,如果不包含此字段,则意味着会使用绝对设置 + /// 以“[Action]”表示当前方法名,如果不包含此字段,则意味着会使用绝对设置 + /// + /// + /// + /// + public RouterAttribute(string routeTemple) + { + if (!routeTemple.StartsWith("/")) + { + routeTemple = routeTemple.Insert(0, "/"); + } + RouteTemple = routeTemple; + } + + /// + /// 路由模板。 + /// + public string RouteTemple { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs.meta new file mode 100644 index 0000000..a235e63 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5eaa2900f27edbe47b837aa29e851c79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs new file mode 100644 index 0000000..333fb8a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs @@ -0,0 +1,163 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApiAttribute + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class WebApiAttribute : RpcAttribute + { + private readonly HttpMethodType m_method; + + /// + /// 构造函数。 + /// + /// + public WebApiAttribute(HttpMethodType method) + { + m_method = method; + } + + /// + /// + /// + /// + public override Type[] GetGenericConstraintTypes() + { + return new Type[] { typeof(IWebApiClient) }; + } + + /// + /// 函数类型。 + /// + public HttpMethodType Method => m_method; + + /// + /// + /// + /// + /// + public override string GetInvokenKey(MethodInstance methodInstance) + { + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + if (m_method == HttpMethodType.GET) + { + string actionUrl = GetRouteUrls(methodInstance)[0]; + if (methodInstance.ParameterNames.Length > i) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(actionUrl); + stringBuilder.Append("?"); + for (; i < methodInstance.ParameterNames.Length; i++) + { + stringBuilder.Append(methodInstance.ParameterNames[i] + "={&}".Replace("&", i.ToString())); + if (i != methodInstance.ParameterNames.Length - 1) + { + stringBuilder.Append("&"); + } + } + actionUrl = stringBuilder.ToString(); + } + return $"GET:{actionUrl}"; + } + else if (m_method == HttpMethodType.POST) + { + string actionUrl = GetRouteUrls(methodInstance)[0]; + if (methodInstance.ParameterNames.Length > i + 1) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(actionUrl); + stringBuilder.Append("?"); + for (; i < methodInstance.ParameterNames.Length - 1; i++) + { + stringBuilder.Append(methodInstance.ParameterNames[i] + "={&}".Replace("&", i.ToString())); + if (i != methodInstance.ParameterNames.Length - 2) + { + stringBuilder.Append("&"); + } + } + actionUrl = stringBuilder.ToString(); + } + return $"POST:{actionUrl}"; + } + else + { + return base.GetInvokenKey(methodInstance); + } + } + + /// + /// 获取路由路径。 + /// 路由路径的第一个值会被当做调用值。 + /// + /// + /// + public virtual string[] GetRouteUrls(MethodInstance methodInstance) + { + if (methodInstance.GetAttribute() is WebApiAttribute webApiAttribute) + { + List urls = new List(); + + var attrs = methodInstance.Info.GetCustomAttributes(typeof(RouterAttribute), true); + if (attrs.Length > 0) + { + foreach (RouterAttribute item in attrs) + { + string url = item.RouteTemple.ToLower() + .Replace("[api]", methodInstance.ServerType.Name) + .Replace("[action]", webApiAttribute.GetMethodName(methodInstance, false)).ToLower(); + + if (!urls.Contains(url)) + { + urls.Add(url); + } + } + } + else + { + attrs = methodInstance.ServerType.GetCustomAttributes(typeof(RouterAttribute), true); + if (attrs.Length > 0) + { + foreach (RouterAttribute item in attrs) + { + string url = item.RouteTemple.ToLower() + .Replace("[api]", methodInstance.ServerType.Name) + .Replace("[action]", webApiAttribute.GetMethodName(methodInstance, false)).ToLower(); + + if (!urls.Contains(url)) + { + urls.Add(url); + } + } + } + else + { + urls.Add($"/{methodInstance.Info.DeclaringType.Name}/{methodInstance.Name}".ToLower()); + } + } + + return urls.ToArray(); + } + return default; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs.meta new file mode 100644 index 0000000..5d1a5c4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac457a8d3d12ef7498c5b30124c51363 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common.meta new file mode 100644 index 0000000..da1ff80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2eb042609b1f3134d948edccec52bc4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs new file mode 100644 index 0000000..2e0eb81 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 结果状态 + /// + public class ActionResult + { + /// + /// 状态类型 + /// + public InvokeStatus Status { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs.meta new file mode 100644 index 0000000..fdcc719 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/ActionResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0d1d8ed7a8dfe6409017ff5791911ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs new file mode 100644 index 0000000..91dd15f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi调用上下文 + /// + internal class WebApiCallContext : IWebApiCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// Http上下文 + /// + public HttpContext HttpContext { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs.meta new file mode 100644 index 0000000..60dc054 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a239e4d4fd0ef8419472b0dfbd7a518 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components.meta new file mode 100644 index 0000000..51eb449 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22136efba17edba4e90fbebf21fb52b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs new file mode 100644 index 0000000..5d6a24a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs @@ -0,0 +1,255 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi客户端 + /// + public class WebApiClient : HttpClientBase, IWebApiClient + { + /// + /// 构造函数 + /// + public WebApiClient() + { + m_stringConverter = new StringConverter(); + } + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + private readonly StringConverter m_stringConverter; + + /// + /// 字符串转化器 + /// + public StringConverter StringConverter => m_stringConverter; + + #region RPC调用 + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + string[] strs = method.Split(':'); + if (strs.Length != 2) + { + throw new RpcException("不是有效的url请求。"); + } + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + HttpRequest request = new HttpRequest(); + + switch (strs[0]) + { + case TouchSocketHttpUtility.Get: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsGet(); + break; + } + case TouchSocketHttpUtility.Post: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsPost(); + if (parameters.Length > 0) + { + request.FromJson(parameters[parameters.Length - 1].ToJson()); + } + break; + } + default: + break; + } + + HttpResponse response = RequestContent(request, false, invokeOption.Timeout, invokeOption.Token); + + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return default; + } + + if (response.StatusCode == "200") + { + return (T)m_stringConverter.ConvertFrom(response.GetBody(), typeof(T)); + } + else if (response.StatusCode == "422") + { + throw new RpcException(response.GetBody().FromJson().Message); + } + else + { + throw new RpcException(response.StatusMessage); + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + string[] strs = method.Split(':'); + if (strs.Length != 2) + { + throw new RpcException("不是有效的url请求。"); + } + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + HttpRequest request = new HttpRequest(); + + switch (strs[0]) + { + case TouchSocketHttpUtility.Get: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsGet(); + break; + } + case TouchSocketHttpUtility.Post: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsPost(); + if (parameters.Length > 0) + { + request.FromJson(parameters[parameters.Length - 1].ToJson()); + } + break; + } + default: + break; + } + HttpResponse response = RequestContent(request, false, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return; + } + + if (response.StatusCode == "200") + { + return; + } + else if (response.StatusCode == "422") + { + throw new RpcException(response.GetBody().FromJson().Message); + } + else + { + throw new RpcException(response.StatusMessage); + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(method, invokeOption, parameters); + }); + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(method, invokeOption, parameters); + }); + } + + #endregion RPC调用 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs.meta new file mode 100644 index 0000000..f628d99 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5cf4b0fa3c7e4347afdaac1ac6dfa88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config.meta new file mode 100644 index 0000000..9eec16b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3fbac60b561304445afc9ac43c9d3edb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs new file mode 100644 index 0000000..bbdeee1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Sockets +{ + /// + /// WebApiConfigExtensions + /// + public static class WebApiConfigExtensions + { + /// + /// 构建WebApiClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithWebApiClient(this TouchSocketConfig config) where TClient : IWebApiClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建WebApiClient类客户端,并连接 + /// + /// + /// + public static WebApiClient BuildWithWebApiClient(this TouchSocketConfig config) + { + return BuildWithWebApiClient(config); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs.meta new file mode 100644 index 0000000..0d2b925 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57382a23f040c1743b9a449ba2459bcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum.meta new file mode 100644 index 0000000..7221d28 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 091e4de14a111554d9f0ff19108a4e7c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs new file mode 100644 index 0000000..de24acc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 请求函数类型 + /// + public enum HttpMethodType + { + /// + /// 以GET方式。支持调用上下文。 + /// 以该方式时,所有的参数类型必须是基础类型。所有的参数来源均来自url参数。 + /// + GET, + + /// + /// 以Post方式。支持调用上下文。 + /// 以该方式时,可以应对以下情况: + /// + /// 仅有一个参数时,该参数可以为任意类型,且参数来源为Body + /// 当有多个参数时,最后一个参数可以为任意类型,且参数来源为Body,其余参数均必须是基础类型,且来自url参数。 + /// + /// + POST + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs.meta new file mode 100644 index 0000000..43d8220 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 559546987672abd479077d60d39bac73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions.meta new file mode 100644 index 0000000..79ef413 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 13ebc6fcac442254c9c9406a66a3f9b4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs new file mode 100644 index 0000000..0a2b56f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Core +{ + /// + /// WebApiPluginsManagerExtension + /// + public static class WebApiPluginsManagerExtension + { + /// + /// 使用WebApi的插件。仅服务器可用。 + /// + /// + /// + public static WebApiParserPlugin UseWebApi(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..3e83b7b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 557c1264bc050ac4584aeee3ae9b1c93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface.meta new file mode 100644 index 0000000..0bed1dc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6da4e3c7cc200404e84891bc25566a3d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs new file mode 100644 index 0000000..17c1ab2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IHttpCallContext + /// + public interface IHttpCallContext : ICallContext + { + /// + /// Http上下文 + /// + HttpContext HttpContext { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs.meta new file mode 100644 index 0000000..2cba6dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41564e383c0df9c4693ddb88ebff4fb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs new file mode 100644 index 0000000..ec53726 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IWebApiCallContext + /// + public interface IWebApiCallContext : IHttpCallContext + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs.meta new file mode 100644 index 0000000..eb24621 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18587a2e6d8cd4b4eb36ed5a54091069 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs new file mode 100644 index 0000000..f1b7140 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IWebApiClient + /// + public interface IWebApiClient : IRpcClient, IHttpClient + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs.meta new file mode 100644 index 0000000..cd40edd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 433879561008c3941a55a652fd41c2bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins.meta new file mode 100644 index 0000000..e930c9c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7aa359e9062bd7439b84757e8129674 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs new file mode 100644 index 0000000..564c368 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs @@ -0,0 +1,358 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi解析器 + /// + public class WebApiParserPlugin : HttpPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private readonly StringConverter m_converter; + private RpcStore m_rpcStore; + + /// + /// 构造函数 + /// + public WebApiParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + m_converter = new StringConverter(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// 转化器 + /// + public StringConverter Converter => m_converter; + + /// + /// 获取路由映射图 + /// + public ActionMap RouteMap => m_actionMap; + + /// + /// 所属服务器 + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_actionMap.TryGetMethodInstance(e.Context.Request.RelativeURL.ToLower(), out MethodInstance methodInstance)) + { + e.Handled = true; + + InvokeResult invokeResult = new InvokeResult(); + object[] ps = null; + WebApiCallContext callContext = new WebApiCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance + }; + if (methodInstance.IsEnable) + { + try + { + ps = new object[methodInstance.Parameters.Length]; + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[i] = callContext; + i++; + } + if (e.Context.Request.Query == null) + { + for (; i < methodInstance.Parameters.Length; i++) + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + else + { + for (; i < methodInstance.Parameters.Length; i++) + { + string value = e.Context.Request.Query.Get(methodInstance.ParameterNames[i]); + if (!value.IsNullOrEmpty()) + { + ps[i] = m_converter.ConvertFrom(value, methodInstance.ParameterTypes[i]); + } + else + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + if (e.Context.Response.Responsed) + { + return; + } + HttpResponse httpResponse = e.Context.Response; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + httpResponse.FromJson(m_converter.ConvertTo(invokeResult.Result)).SetStatus(); + break; + } + case InvokeStatus.UnFound: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("404"); + break; + } + case InvokeStatus.UnEnable: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("405"); + break; + } + case InvokeStatus.InvocationException: + case InvokeStatus.Exception: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("422"); + break; + } + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + httpResponse.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + + base.OnGet(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_actionMap.TryGetMethodInstance(e.Context.Request.RelativeURL.ToLower(), out MethodInstance methodInstance)) + { + e.Handled = true; + + var invokeResult = new InvokeResult(); + object[] ps = null; + var callContext = new WebApiCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance + }; + if (methodInstance.IsEnable) + { + try + { + int index; + ps = new object[methodInstance.Parameters.Length]; + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[i] = callContext; + i++; + index = methodInstance.Parameters.Length - 2; + } + else + { + index = methodInstance.Parameters.Length - 1; + } + if (e.Context.Request.Query == null) + { + for (; i < methodInstance.Parameters.Length - 1; i++) + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + else + { + for (; i < methodInstance.Parameters.Length - 1; i++) + { + string value = e.Context.Request.Query.Get(methodInstance.ParameterNames[i]); + if (!value.IsNullOrEmpty()) + { + ps[i] = m_converter.ConvertFrom(value, methodInstance.ParameterTypes[i]); + } + else + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + } + + if (index >= 0) + { + string str = e.Context.Request.GetBody(); + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + index++; + } + ps[index] = m_converter.ConvertFrom(str, methodInstance.ParameterTypes[index]); + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + if (e.Context.Response.Responsed) + { + return; + } + HttpResponse httpResponse = e.Context.Response; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + httpResponse.FromJson(m_converter.ConvertTo(invokeResult.Result)).SetStatus(); + break; + } + case InvokeStatus.UnFound: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("404", invokeResult.Status.ToString()); + break; + } + case InvokeStatus.UnEnable: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("405", invokeResult.Status.ToString()); + break; + } + case InvokeStatus.InvocationException: + case InvokeStatus.Exception: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("422", invokeResult.Status.ToString()); + break; + } + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + httpResponse.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + + base.OnPost(client, e); + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is WebApiAttribute attribute) + { + string[] actionUrls = attribute.GetRouteUrls(methodInstance); + if (actionUrls != null) + { + foreach (var item in actionUrls) + { + m_actionMap.Add(item, methodInstance); + } + } + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is WebApiAttribute attribute) + { + string[] actionUrls = attribute.GetRouteUrls(methodInstance); + if (actionUrls != null) + { + foreach (var item in actionUrls) + { + m_actionMap.Remove(item); + } + } + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs.meta new file mode 100644 index 0000000..9ebeb00 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b39cbaf77cc151444a389e733fc14d29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc.meta new file mode 100644 index 0000000..15ae015 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09190cc201f97a540a30ad902fd87d38 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute.meta new file mode 100644 index 0000000..29d8511 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d24e96b064261634e9fa2a9cfc108850 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs new file mode 100644 index 0000000..a9e4a74 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// 适用于XmlRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class XmlRpcAttribute : RpcAttribute + { + /// + /// 适用于XmlRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public XmlRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于XmlRpc的标记. + /// + /// + public XmlRpcAttribute(string invokenKey) + { + InvokeKey = invokenKey; + } + + + /// + /// + /// + /// + public override Type[] GetGenericConstraintTypes() + { + return new Type[] { typeof(IXmlRpcClient) }; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs.meta new file mode 100644 index 0000000..bdeb3b7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea4913be48d33d1468fe1fefde543872 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common.meta new file mode 100644 index 0000000..cf9a8ed --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0fa95533d232084882880c3212234e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs new file mode 100644 index 0000000..60d0327 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Reflection; +using System.Text; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + internal static class XmlDataTool + { + public static object GetValue(XmlNode valueNode, Type type) + { + if (valueNode == null) + { + return type.GetDefault(); + } + switch (valueNode.Name) + { + case "boolean": + { + return bool.Parse(valueNode.InnerText); + } + case "i4": + case "int": + { + return int.Parse(valueNode.InnerText); + } + case "double": + { + return double.Parse(valueNode.InnerText); + } + case "dateTime.iso8601": + { + return DateTime.Parse(valueNode.InnerText); + } + case "base64": + { + return valueNode.InnerText; + } + case "struct": + { + object instance = Activator.CreateInstance(type); + foreach (XmlNode memberNode in valueNode.ChildNodes) + { + string name = memberNode.SelectSingleNode("name").InnerText; + PropertyInfo property = type.GetProperty(name); + property.SetValue(instance, GetValue(memberNode.SelectSingleNode("value").FirstChild, property.PropertyType)); + } + return instance; + } + case "arrays": + case "array": + { + if (type.GetElementType() != null) + { + XmlNode dataNode = valueNode.SelectSingleNode("data"); + Array array = Array.CreateInstance(type.GetElementType(), dataNode.ChildNodes.Count); + + int index = 0; + foreach (XmlNode arrayValueNode in dataNode.ChildNodes) + { + array.SetValue(GetValue(arrayValueNode.FirstChild, type.GetElementType()), index); + index++; + } + return array; + } + else if (type.GetGenericArguments().Length == 1) + { + XmlNode dataNode = valueNode.SelectSingleNode("data"); + IList array = (IList)Activator.CreateInstance(type); + + foreach (XmlNode arrayValueNode in dataNode.ChildNodes) + { + array.Add(GetValue(arrayValueNode.FirstChild, type.GetGenericArguments()[0])); + } + return array; + } + return type.GetDefault(); + } + default: + case "string": + { + return valueNode.InnerText; + } + } + } + + public static HttpRequest CreateRequest(string host, string url, string method, object[] parameters) + { + XmlDocument xml = new XmlDocument(); + + XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty); + xml.AppendChild(xmlDecl); + + XmlElement xmlElement = xml.CreateElement("methodCall"); + xml.AppendChild(xmlElement); + + XmlElement methodNameElement = xml.CreateElement("methodName"); + methodNameElement.InnerText = method; + xmlElement.AppendChild(methodNameElement); + + XmlElement paramsElement = xml.CreateElement("params"); + xmlElement.AppendChild(paramsElement); + + if (parameters != null) + { + foreach (var param in parameters) + { + XmlElement paramElement = xml.CreateElement("param"); + paramsElement.AppendChild(paramElement); + + XmlElement valueElement = xml.CreateElement("value"); + paramElement.AppendChild(valueElement); + + CreateParam(xml, valueElement, param); + } + } + + HttpRequest request = new HttpRequest(); + request.FromXML(xml.OuterXml) + .InitHeaders() + .SetUrl(url) + .SetHost(host) + .AsPost(); + return request; + } + + public static void CreateParam(XmlDocument xml, XmlNode xmlNode, object value) + { + if (value == null) + { + return; + } + if (value is int) + { + XmlElement valueElement = xml.CreateElement("i4"); + valueElement.InnerText = value.ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is bool) + { + XmlElement valueElement = xml.CreateElement("boolean"); + valueElement.InnerText = (value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is double) + { + XmlElement valueElement = xml.CreateElement("double"); + valueElement.InnerText = ((double)value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is string) + { + XmlElement valueElement = xml.CreateElement("string"); + valueElement.InnerText = value.ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is DateTime) + { + XmlElement valueElement = xml.CreateElement("dateTime.iso8601"); + valueElement.InnerText = ((DateTime)value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is byte[]) + { + XmlElement valueElement = xml.CreateElement("base64"); + string str = Convert.ToBase64String((byte[])value); + valueElement.InnerText = str; + xmlNode.AppendChild(valueElement); + } + else if (typeof(IList).IsAssignableFrom(value.GetType())) + { + IList array = (IList)value; + XmlElement arrayElement; + + arrayElement = xml.CreateElement("array"); + + xmlNode.AppendChild(arrayElement); + + XmlElement dataElememt = xml.CreateElement("data"); + arrayElement.AppendChild(dataElememt); + + foreach (var item in array) + { + XmlElement valueElement = xml.CreateElement("value"); + dataElememt.AppendChild(valueElement); + CreateParam(xml, valueElement, item); + } + } + else + { + XmlElement valueElement = xml.CreateElement("struct"); + xmlNode.AppendChild(valueElement); + + PropertyInfo[] propertyInfos = value.GetType().GetProperties(); + foreach (var propertyInfo in propertyInfos) + { + XmlElement memberElement = xml.CreateElement("member"); + valueElement.AppendChild(memberElement); + + XmlElement nameElement = xml.CreateElement("name"); + nameElement.InnerText = propertyInfo.Name; + memberElement.AppendChild(nameElement); + + XmlElement oValueElement = xml.CreateElement("value"); + memberElement.AppendChild(oValueElement); + + object oValue = propertyInfo.GetValue(value); + CreateParam(xml, oValueElement, oValue); + } + } + } + + public static void CreatResponse(HttpResponse httpResponse, object value) + { + XmlDocument xml = new XmlDocument(); + + XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty); + xml.AppendChild(xmlDecl); + + XmlElement xmlElement = xml.CreateElement("methodResponse"); + + xml.AppendChild(xmlElement); + + XmlElement paramsElement = xml.CreateElement("params"); + xmlElement.AppendChild(paramsElement); + + XmlElement paramElement = xml.CreateElement("param"); + paramsElement.AppendChild(paramElement); + + XmlElement valueElement = xml.CreateElement("value"); + paramElement.AppendChild(valueElement); + + CreateParam(xml, valueElement, value); + + ByteBlock xmlBlock = new ByteBlock(); + xml.Save(xmlBlock); + + string xmlString = Encoding.UTF8.GetString(xmlBlock.Buffer, 0, xmlBlock.Len); + + httpResponse.FromXML(xmlString); + xmlBlock.Dispose(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs.meta new file mode 100644 index 0000000..10bb69b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73a3c30184c472e4bae005b1ec2cbd24 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs new file mode 100644 index 0000000..0c53566 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + internal class XmlRpcCallContext : IXmlRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + public object Caller { get; internal set; } + + public MethodInstance MethodInstance { get; internal set; } + + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// + /// + public HttpContext HttpContext { get; internal set; } + + public string XmlString { get; internal set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs.meta new file mode 100644 index 0000000..a79c218 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d42426ee07fdaac4eb7bb32ed121758f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components.meta new file mode 100644 index 0000000..3a87f10 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d51e8acb4092c8f49b920fbdf5691cd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs new file mode 100644 index 0000000..f5b275e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// XmlRpc客户端 + /// + public class XmlRpcClient : HttpClientBase, IXmlRpcClient + { + private readonly object m_invokeLocker = new object(); + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + lock (m_invokeLocker) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + using (ByteBlock byteBlock = new ByteBlock(BufferLength)) + { + HttpRequest request = XmlDataTool.CreateRequest(RemoteIPHost.Host, RemoteIPHost.GetUrlPath(), method, parameters); + + HttpResponse response = RequestContent(request, invokeOption.FeedbackType == FeedbackType.OnlySend, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return default; + } + + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + else + { + XmlDocument xml = new XmlDocument(); + xml.LoadXml(response.GetBody()); + XmlNode paramNode = xml.SelectSingleNode("methodResponse/params/param"); + if (paramNode != null) + { + return (T)XmlDataTool.GetValue(paramNode.FirstChild.FirstChild, typeof(T)); + } + return default; + } + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + lock (m_invokeLocker) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + using (ByteBlock byteBlock = new ByteBlock(BufferLength)) + { + HttpRequest request = XmlDataTool.CreateRequest(RemoteIPHost.Host, RemoteIPHost.GetUrlPath(), method, parameters); + var response = RequestContent(request, invokeOption.FeedbackType == FeedbackType.OnlySend, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return; + } + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(method, invokeOption, parameters); + }); + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(method, invokeOption, parameters); + }); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs.meta new file mode 100644 index 0000000..39ddd80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2e90356af25e954e9de0f8ca2fde202 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config.meta new file mode 100644 index 0000000..5b049c9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fd71a8fde2a38c64db4fa6bfc4fc31fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs new file mode 100644 index 0000000..617b39a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.XmlRpc; + +namespace TouchSocket.Sockets +{ + /// + /// XmlRpcConfigExtensions + /// + public static class XmlRpcConfigExtensions + { + /// + /// 构建XmlRpcClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithXmlRpcClient(this TouchSocketConfig config) where TClient : IXmlRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建XmlRpcClient类客户端,并连接 + /// + /// + /// + public static XmlRpcClient BuildWithXmlRpcClient(this TouchSocketConfig config) + { + return BuildWithXmlRpcClient(config); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs.meta new file mode 100644 index 0000000..c7ec817 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a46538a331ad9f4409e8b084cbb3df3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions.meta new file mode 100644 index 0000000..a63e03f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43a65572113cad449b6cb6f9b76f1e2c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs new file mode 100644 index 0000000..2db2803 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.XmlRpc; + +namespace TouchSocket.Core +{ + /// + /// XmlRpcPluginsManagerExtension + /// + public static class XmlRpcPluginsManagerExtension + { + /// + /// 使用XmlRpc的插件。仅服务器可用。 + /// + /// + /// + public static XmlRpcParserPlugin UseXmlRpc(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..4d4adef --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7336411d81cbcc64680558b25b222325 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface.meta new file mode 100644 index 0000000..e826f1e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9c3804907e565c47b3d51385dfcb5af +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs new file mode 100644 index 0000000..957ef42 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// IXmlRpcCallContext + /// + public interface IXmlRpcCallContext : IHttpCallContext + { + /// + /// XmlRpc的调用字符串。 + /// + string XmlString { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs.meta new file mode 100644 index 0000000..70a39db --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b0181efe67bb6b47b6c663e89d457d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs new file mode 100644 index 0000000..50e9e6b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// IWebApiClient + /// + public interface IXmlRpcClient : IRpcClient, IHttpClient + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs.meta new file mode 100644 index 0000000..7f41fae --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e09595ab39266a14f8e4215f71a868b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins.meta new file mode 100644 index 0000000..659ca2a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa31f850bdfb4ca48bcdcad4cae8af4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs new file mode 100644 index 0000000..f09ca59 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs @@ -0,0 +1,217 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// XmlRpc解析器 + /// + public class XmlRpcParserPlugin : HttpPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private RpcStore m_rpcStore; + private string m_xmlRpcUrl = "/xmlrpc"; + + /// + /// 构造函数 + /// + public XmlRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// XmlRpc调用 + /// + public ActionMap ActionMap => m_actionMap; + + /// + /// 所属服务器 + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + public string XmlRpcUrl + { + get => m_xmlRpcUrl; + set => m_xmlRpcUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is XmlRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is XmlRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + /// + /// + public XmlRpcParserPlugin SetXmlRpcUrl(string xmlRpcUrl) + { + XmlRpcUrl = xmlRpcUrl; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_xmlRpcUrl == "/" || e.Context.Request.UrlEquals(m_xmlRpcUrl)) + { + e.Handled = true; + + XmlDocument xml = new XmlDocument(); + string xmlstring = e.Context.Request.GetBody(); + xml.LoadXml(xmlstring); + XmlNode methodName = xml.SelectSingleNode("methodCall/methodName"); + string actionKey = methodName.InnerText; + + object[] ps = null; + InvokeResult invokeResult = new InvokeResult(); + XmlRpcCallContext callContext = null; + + if (m_actionMap.TryGetMethodInstance(actionKey, out MethodInstance methodInstance)) + { + if (methodInstance.IsEnable) + { + try + { + callContext = new XmlRpcCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance, + XmlString = xmlstring + }; + ps = new object[methodInstance.ParameterNames.Length]; + XmlNode paramsNode = xml.SelectSingleNode("methodCall/params"); + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[0] = callContext; + int index = 1; + foreach (XmlNode paramNode in paramsNode.ChildNodes) + { + XmlNode valueNode = paramNode.FirstChild.FirstChild; + ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); + index++; + } + } + else + { + int index = 0; + foreach (XmlNode paramNode in paramsNode.ChildNodes) + { + XmlNode valueNode = paramNode.FirstChild.FirstChild; + ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); + index++; + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + invokeResult.Message = "服务不可用"; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + invokeResult.Message = "没有找到这个服务。"; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + HttpResponse httpResponse = e.Context.Response; + + ByteBlock byteBlock = new ByteBlock(); + + if (invokeResult.Status == InvokeStatus.Success) + { + XmlDataTool.CreatResponse(httpResponse, invokeResult.Result); + } + else + { + httpResponse.StatusCode = "201"; + httpResponse.StatusMessage = invokeResult.Message; + } + try + { + httpResponse.Answer(); + } + finally + { + byteBlock.Dispose(); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + base.OnPost(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs.meta new file mode 100644 index 0000000..f1824a8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 023f9801545af6145a1836df8d41d8a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets.meta new file mode 100644 index 0000000..5f5b2a0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a457e2323a93152459c73a9212be6652 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs new file mode 100644 index 0000000..e47fcd3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 通讯基类 + /// + public abstract class BaseSocket : DependencyObject, ISocket + { + /// + /// 通讯基类 + /// + public BaseSocket() + { + SyncRoot = new object(); + } + + private int m_bufferLength; + + /// + /// 数据交互缓存池限制,min=1024 byte + /// + public virtual int BufferLength + { + get => m_bufferLength; + set + { + if (value < 1024) + { + value = 1024; + } + m_bufferLength = value; + } + } + + /// + /// 同步根。 + /// + protected object SyncRoot; + + /// + /// 日志记录器 + /// + public ILog Logger { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs.meta new file mode 100644 index 0000000..97c7a00 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/BaseSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3aacbaf3568fb8649a0f7a0c58483a9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common.meta new file mode 100644 index 0000000..7c33962 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 059f8609c23c29c4bab74b3f87b0631a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs new file mode 100644 index 0000000..ec9989d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 延迟发送器 + /// + public sealed class DelaySender : DisposableObject + { + private readonly ReaderWriterLockSlim m_lockSlim; + private readonly Action m_onError; + private readonly IntelligentDataQueue m_queueDatas; + private readonly Socket m_socket; + private readonly Timer m_timer; + private volatile bool m_sending; + + /// + /// 延迟发送器 + /// + /// + /// + /// + public DelaySender(Socket socket, int queueLength, Action onError) + { + m_socket = socket; + m_onError = onError; + m_queueDatas = new IntelligentDataQueue(queueLength); + m_lockSlim = new ReaderWriterLockSlim(); + m_timer = new Timer(TimerRun, null, 10, 10); + } + + /// + /// 延迟包最大尺寸,默认1024*512字节。 + /// + public int DelayLength { get; set; } = 1024 * 512; + + /// + /// 是否处于发送状态 + /// + public bool Sending + { + get + { + using (new ReadLock(m_lockSlim)) + { + return m_sending; + } + } + + private set + { + using (new WriteLock(m_lockSlim)) + { + m_sending = value; + } + } + } + + /// + /// 发送 + /// + public void Send(QueueDataBytes dataBytes) + { + m_queueDatas.Enqueue(dataBytes); + if (SwitchToRun()) + { + ThreadPool.QueueUserWorkItem(BeginSend); + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_queueDatas.Clear(); + base.Dispose(disposing); + } + + private void BeginSend(object o) + { + try + { + byte[] buffer = BytePool.Default.GetByteCore(DelayLength); + while (!DisposedValue) + { + try + { + if (TryGet(buffer, out QueueDataBytes asyncByte)) + { + m_socket.AbsoluteSend(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + } + else + { + break; + } + } + catch (Exception ex) + { + m_onError?.Invoke(ex); + break; + } + } + BytePool.Default.Recycle(buffer); + Sending = false; + } + catch + { + } + } + + private bool SwitchToRun() + { + using (new WriteLock(m_lockSlim)) + { + if (m_sending) + { + return false; + } + else + { + m_sending = true; + return true; + } + } + } + + private void TimerRun(object state) + { + if (SwitchToRun()) + { + BeginSend(null); + } + } + + private bool TryGet(byte[] buffer, out QueueDataBytes asyncByteDe) + { + int len = 0; + int surLen = buffer.Length; + while (true) + { + if (m_queueDatas.TryPeek(out QueueDataBytes asyncB)) + { + if (surLen > asyncB.Length) + { + if (m_queueDatas.TryDequeue(out QueueDataBytes asyncByte)) + { + Array.Copy(asyncByte.Buffer, asyncByte.Offset, buffer, len, asyncByte.Length); + len += asyncByte.Length; + surLen -= asyncByte.Length; + } + } + else if (asyncB.Length > buffer.Length) + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = asyncB; + return true; + } + } + else + { + break; + } + } + else + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = default; + return false; + } + } + } + asyncByteDe = new QueueDataBytes(buffer, 0, len); + return true; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs.meta new file mode 100644 index 0000000..ed55af6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/DelaySender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89ae7fc0098688e488e0aaeb5e9a4f2d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs new file mode 100644 index 0000000..57d6793 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs @@ -0,0 +1,214 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// IP解析映射 + /// + /// 支持端口,ip,域名等。具体格式如下: + /// + /// 端口:直接按入参,该操作一般在监听时使用。 + /// ip:按127.0.0.1:7789入参。 + /// 域名:按tcp://127.0.0.1:7789、或者http://baidu.com入参。 + /// + /// + /// + public class IPHost + { + /// + /// IP解析映射 + /// + /// 支持端口,ip,域名等。具体格式如下: + /// + /// 端口:直接按入参,该操作一般在监听时使用。 + /// ip:按127.0.0.1:7789入参。 + /// 域名:按tcp://127.0.0.1:7789、或者http://baidu.com入参。 + /// + /// + /// + /// + public IPHost(string host) + { + if (TouchSocketUtility.IsURL(host)) + { + IsUri = true; + Uri = new Uri(host); + if (Uri.Port > 0) + { + Host = $"{Uri.Host}:{Uri.Port}"; + } + else + { + Host = Uri.Host; + } + if (TouchSocketUtility.IsIPv4(Uri.Host) || TouchSocketUtility.IsIPV6(Uri.Host)) + { + Analysis(Uri.Host, Uri.Port.ToString()); + } + else + { + if (HostNameToIP(Uri.Host, out IPAddress[] addresses)) + { + Analysis(addresses[0].ToString(), Uri.Port.ToString()); + } + } + } + else + { + Host = host; + int r = host.LastIndexOf(":"); + string ip = host.Substring(0, r); + Analysis(ip, host.Substring(r + 1, host.Length - (r + 1))); + } + } + + /// + /// 从IPAddress和端口号 + /// + /// + /// + public IPHost(IPAddress iPAddress, int port) : this($"{iPAddress}:{port}") + { + } + + /// + /// 从端口号创建。 + /// + /// + public IPHost(int port) : this($"0.0.0.0:{port}") + { + } + + /// + /// 寻址方案 + /// + public AddressFamily AddressFamily { get; private set; } + + /// + /// 终结点 + /// + public IPEndPoint EndPoint { get; private set; } + + /// + /// 具有端口信息的host + /// + public string Host { get; private set; } + + /// + /// IP + /// + public string IP { get; private set; } + + /// + /// 是否为Uri + /// + public bool IsUri { get; private set; } + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// 统一资源标识 + /// + public Uri Uri { get; private set; } + + /// + /// 解析一个组的地址。 + /// + /// + /// + public static IPHost[] ParseIPHosts(string[] strs) + { + List iPs = new List(); + foreach (var item in strs) + { + iPs.Add(new IPHost(item)); + } + return iPs.ToArray(); + } + + /// + /// 获取Url全路径 + /// + /// + public string GetUrlPath() + { + if (IsUri) + { + return Uri.PathAndQuery; + } + return default; + } + + /// + /// 返回EndPoint字符串 + /// + /// + public override string ToString() + { + return EndPoint == null ? null : EndPoint.ToString(); + } + + private static bool HostNameToIP(string hostname, out IPAddress[] address) + { + try + { + IPHostEntry hostInfo = Dns.GetHostEntry(hostname); + address = hostInfo.AddressList; + if (address.Length > 0) + { + return true; + } + + return false; + } + catch + { + address = null; + return false; + } + } + + private void Analysis(string ip, string port) + { + try + { + int portNum = int.Parse(port); + IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), portNum); + if (ip.Contains(":")) + { + AddressFamily = AddressFamily.InterNetworkV6; + } + else + { + AddressFamily = AddressFamily.InterNetwork; + } + EndPoint = endPoint; + IP = ip; + Port = portNum; + } + catch (Exception ex) + { + throw new Exception($"IPHost初始化失败,信息:{ex.Message}", ex); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs.meta new file mode 100644 index 0000000..16cdcf0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/IPHost.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d24f3d8b9f0b5b94ebca6f121392d190 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs new file mode 100644 index 0000000..98bfb6d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Runtime.InteropServices; + +namespace TouchSocket.Sockets +{ + /// + /// 保活机制 + /// + public class KeepAliveValue + { + /// + /// 保活机制 + /// + public byte[] KeepAliveTime + { + get + { + uint dummy = 0; + byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; + BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); + BitConverter.GetBytes(Interval).CopyTo(inOptionValues, Marshal.SizeOf(dummy)); + BitConverter.GetBytes(AckInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2); + return inOptionValues; + } + } + + /// + /// 是否启用保活。默认为True。 + /// + public bool Enable { get; set; } = true; + + /// + /// 发送间隔,默认20*1000ms + /// + public uint Interval { get; set; } = 20 * 1000; + + /// + /// 确认间隔,默认2*1000ms + /// + public uint AckInterval { get; set; } = 2 * 1000; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs.meta new file mode 100644 index 0000000..2f6c56e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/KeepAliveValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c80fab20b80e0174b92832ba54f558c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs new file mode 100644 index 0000000..71424da --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// 网络监听器 + /// + public class NetworkMonitor + { + /// + /// 构造函数 + /// + /// + /// + public NetworkMonitor(IPHost iPHost, Socket socket) + { + this.iPHost = iPHost; + this.socket = socket ?? throw new ArgumentNullException(nameof(socket)); + } + + private readonly IPHost iPHost; + + /// + /// 监听地址组 + /// + public IPHost IPHost => iPHost; + + private readonly Socket socket; + + /// + /// Socket组件 + /// + public Socket Socket => socket; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs.meta new file mode 100644 index 0000000..d3f5c71 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/NetworkMonitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a71f93175b9256a41947292c12d84513 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options.meta new file mode 100644 index 0000000..28ae9b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f755a3ecfd42b3341869bf98a4f819ca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs new file mode 100644 index 0000000..600b758 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Security.Cryptography.X509Certificates; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端Ssl验证 + /// + public class ClientSslOption : SslOption + { + /// + /// 构造函数 + /// + public ClientSslOption() + { + X509Store store = new X509Store(StoreName.Root); + store.Open(OpenFlags.ReadWrite); + ClientCertificates = store.Certificates; + store.Close(); + } + + private string targetHost; + + /// + /// 目标Host + /// + public string TargetHost + { + get => targetHost; + set => targetHost = value; + } + + /// + /// 验证组合 + /// + public X509CertificateCollection ClientCertificates { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs.meta new file mode 100644 index 0000000..f1b13ba --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ClientSslOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 568e12ecd1dc45147bc2c82b39d3134b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs new file mode 100644 index 0000000..e266b16 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// DelaySenderOption + /// + public class DelaySenderOption + { + /// + /// 延迟队列最大尺寸,默认1024*1024*10字节。 + /// + public int QueueLength { get; set; } = 1024 * 1024 * 10; + + /// + /// 延迟包最大尺寸,默认1024*512字节。 + /// + public int DelayLength { get; set; } = 1024 * 512; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs.meta new file mode 100644 index 0000000..e75e122 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 171090f3c1937af4ebf84aa4a034d2e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs new file mode 100644 index 0000000..3e75ddb --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Security.Cryptography.X509Certificates; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器Ssl设置 + /// + public class ServiceSslOption : SslOption + { + private X509Certificate certificate; + + /// + /// 证书 + /// + public X509Certificate Certificate + { + get => certificate; + set => certificate = value; + } + + private bool clientCertificateRequired; + + /// + /// 该值指定是否向客户端请求证书用于进行身份验证。 请注意,这只是一个请求 - 如果没有提供任何证书,服务器仍然可接受连接请求 + /// + public bool ClientCertificateRequired + { + get => clientCertificateRequired; + set => clientCertificateRequired = value; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs.meta new file mode 100644 index 0000000..f41e748 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bc804e5f8a3f3741975d5fce6e2b5cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs new file mode 100644 index 0000000..cfed151 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Security; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace TouchSocket.Sockets +{ + /// + /// Ssl配置 + /// + public abstract class SslOption + { + /// + /// Ssl配置 + /// + public SslOption() + { + CertificateValidationCallback = this.OnCertificateValidationCallback; + } + + private bool OnCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + + /// + /// 协议版本 + /// + public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Default | + SslProtocols.Tls | SslProtocols.Tls11; + + /// + /// 该值指定身份验证期间是否检查证书吊销列表 + /// + public bool CheckCertificateRevocation { get; set; } = false; + + /// + /// SSL验证回调。 + /// + public RemoteCertificateValidationCallback CertificateValidationCallback { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs.meta new file mode 100644 index 0000000..06b29a7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Options/SslOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb90efb4945b1104387d54da9bc2f43a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs new file mode 100644 index 0000000..09e1739 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 协议类 + /// + public struct Protocol + { + /// + /// 值 + /// + private readonly string value; + + /// + /// 表示无协议 + /// + public static readonly Protocol None = new Protocol(); + + /// + /// 获取http协议 + /// + public static readonly Protocol Http = new Protocol("http"); + + /// + /// TCP协议 + /// + public static readonly Protocol TCP = new Protocol("tcp"); + + /// + /// UDP协议 + /// + public static readonly Protocol UDP = new Protocol("udp"); + + /// + /// 获取WebSocket协议 + /// + public static readonly Protocol WebSocket = new Protocol("ws"); + + /// + /// 表示 + /// + /// 值 + public Protocol(string value) + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentNullException(); + } + this.value = value; + } + + /// + /// 转换为字符串 + /// + /// + public override string ToString() + { + if (string.IsNullOrEmpty(value)) + { + return "None"; + } + return value; + } + + /// + /// 获取哈希码 + /// + /// + public override int GetHashCode() + { + if (value == null) + { + return string.Empty.GetHashCode(); + } + return value.ToLower().GetHashCode(); + } + + /// + /// 比较是否和目标相等 + /// + /// 目标 + /// + public override bool Equals(object obj) + { + if (obj is Protocol) + { + return GetHashCode() == obj.GetHashCode(); + } + return false; + } + + /// + /// 等于 + /// + /// + /// + /// + public static bool operator ==(Protocol a, Protocol b) + { + if (string.IsNullOrEmpty(a.value) && string.IsNullOrEmpty(b.value)) + { + return true; + } + return string.Equals(a.value, b.value, StringComparison.OrdinalIgnoreCase); + } + + /// + /// 不等于 + /// + /// + /// + /// + public static bool operator !=(Protocol a, Protocol b) + { + var state = a == b; + return !state; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs.meta new file mode 100644 index 0000000..52cfe0e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/Protocol.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56fd31c116fcb9e46a3b431f71951d8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs new file mode 100644 index 0000000..e16d942 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端集合 + /// + [DebuggerDisplay("Count={Count}")] + public sealed class SocketClientCollection + { + private readonly ConcurrentDictionary m_tokenDic = new ConcurrentDictionary(); + + /// + /// 数量 + /// + public int Count => m_tokenDic.Count; + + /// + /// 获取SocketClient + /// + /// + /// + public ISocketClient this[string id] + { + get + { + TryGetSocketClient(id, out ISocketClient t); + return t; + } + } + + /// + /// 获取所有的客户端 + /// + /// + public IEnumerable GetClients() + { + return m_tokenDic.Values; + } + + /// + /// 获取ID集合 + /// + /// + public IEnumerable GetIDs() + { + return m_tokenDic.Keys; + } + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + public bool SocketClientExist(string id) + { + if (string.IsNullOrEmpty(id)) + { + return false; + } + + if (m_tokenDic.ContainsKey(id)) + { + return true; + } + return false; + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out ISocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + + return m_tokenDic.TryGetValue(id, out socketClient); + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out TClient socketClient) where TClient : ISocketClient + { + if (string.IsNullOrEmpty(id)) + { + socketClient = default; + return false; + } + + if (m_tokenDic.TryGetValue(id, out ISocketClient client)) + { + socketClient = (TClient)client; + return true; + } + socketClient = default; + return false; + } + + internal bool TryAdd(ISocketClient socketClient) + { + return m_tokenDic.TryAdd(socketClient.ID, socketClient); + } + + internal bool TryRemove(string id, out ISocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + return m_tokenDic.TryRemove(id, out socketClient); + } + + internal bool TryRemove(string id, out TClient socketClient) where TClient : ISocketClient + { + if (string.IsNullOrEmpty(id)) + { + socketClient = default; + return false; + } + + if (m_tokenDic.TryRemove(id, out ISocketClient client)) + { + socketClient = (TClient)client; + return true; + } + socketClient = default; + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs.meta new file mode 100644 index 0000000..9b62885 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/SocketCliectCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0207d61253048440a5be33853625c17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs new file mode 100644 index 0000000..63e581a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text.RegularExpressions; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TouchSocketUtility + /// + public class TouchSocketUtility + { + /// + /// 判断输入的字符串是否是一个超链接 + /// + /// + /// + public static bool IsURL(string input) + { + string pattern = @"^[a-zA-Z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$?"; + Regex regex = new Regex(pattern); + return regex.IsMatch(input); + } + + /// + /// 判断输入的字符串是否是表示一个IP地址 + /// + /// 被比较的字符串 + /// 是IP地址则为True + public static bool IsIPv4(string input) + { + try + { + string[] IPs = input.Split('.'); + Regex regex = new Regex(@"^\d+$"); + for (int i = 0; i < IPs.Length; i++) + { + if (!regex.IsMatch(IPs[i])) + { + return false; + } + if (Convert.ToUInt16(IPs[i]) > 255) + { + return false; + } + } + return true; + } + catch + { + return false; + } + } + + /// + /// 判断输入的字符串是否是合法的IPV6 地址 + /// + /// + /// + public static bool IsIPV6(string input) + { + string pattern = ""; + string temp = input; + string[] strs = temp.Split(':'); + if (strs.Length > 8) + { + return false; + } + int count = StringExtension.HitStringCount(input, "::"); + if (count > 1) + { + return false; + } + else if (count == 0) + { + pattern = @"^([\da-f]{1,4}:){7}[\da-f]{1,4}$"; + + Regex regex = new Regex(pattern); + return regex.IsMatch(input); + } + else + { + pattern = @"^([\da-f]{1,4}:){0,5}::([\da-f]{1,4}:){0,5}[\da-f]{1,4}$"; + Regex regex1 = new Regex(pattern); + return regex1.IsMatch(input); + } + } + + /// + /// 大数据边界 + /// + public const int BigDataBoundary = 1024 * 64; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs.meta new file mode 100644 index 0000000..ceb4a27 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Common/TouchSocketUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0ae513b2a9251740aa80c74e1f85ef0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components.meta new file mode 100644 index 0000000..f76b1e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ef317b124f68494490b8d4b738dd9c9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory.meta new file mode 100644 index 0000000..0100134 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 726061a4cdd727947bab315b3c043c49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs new file mode 100644 index 0000000..68b5ef5 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Client工厂 + /// + public abstract class ClientFactory : DisposableObject where TClient : IClient + { + /// + /// Client工厂 + /// + public ClientFactory() + { + this.MainConfig = new TouchSocketConfig(); + } + + /// + /// 已创建的客户端安全列表,一般不要直接操作。 + /// + public ConcurrentList CreatedClients { get; } = new ConcurrentList(); + + /// + /// 空闲客户端的安全队列,一般不要直接操作。 + /// + public ConcurrentQueue FreeClients { get; } = new ConcurrentQueue(); + + /// + /// 主通信客户端。 + /// + public abstract TClient MainClient { get; } + + /// + /// 主客户端配置 + /// + /// + public virtual TouchSocketConfig MainConfig { get; } + + /// + /// 最大客户端数量。默认10。 + /// + public int MaxCount { get; set; } = 10; + + /// + /// 池中维护的最小客户端数量。默认0。 + /// + public int MinCount { get; set; } + + /// + /// 检验主通信状态。最好在每次操作时都调用。 + /// + /// 如果状态异常,是否进行再次初始化 + /// + public abstract Result CheckStatus(bool tryInit = true); + + /// + /// 检验主通信状态。最好在每次操作时都调用。 + /// + /// 如果状态异常,是否进行再次初始化 + /// + public virtual Task CheckStatusAsync(bool tryInit = true) + { + return Task.Run(() => + { + return this.CheckStatus(tryInit); + }); + } + + /// + /// 清理池中的所有客户端。 + /// + /// + public virtual Task ClearAsync() + { + return Task.Run(() => + { + return this.Clear(); + }); + } + /// + /// 清理池中的所有客户端。 + /// + /// + public virtual int Clear() + { + int count = 0; + foreach (var item in this.CreatedClients) + { + count++; + DisposeClient(item); + } + FreeClients.Clear(); + return count; + } + + /// + /// 释放客户端最后的调用。 + /// + /// + public abstract void DisposeClient(TClient client); + + /// + /// 释放客户端最后的调用。 + /// + /// + /// + public virtual Task DisposeClientAsync(TClient client) + { + return Task.Run(() => + { + this.DisposeClient(client); + }); + } + + /// + /// 获取空闲可用的客户端数量。 + /// + public abstract int GetAvailableCount(); + + /// + /// 获取用于传输的客户端。在此处返回的结果,必须完成基本初始化,例如连接等。 + /// + /// + /// + public abstract TClient GetTransferClient(TimeSpan waitTime); + + /// + /// 判断客户端是不是存活状态。 + /// + /// + /// + public abstract bool IsAlive(TClient client); + + /// + /// 释放使用完成的客户端 + /// + /// + public abstract void ReleaseTransferClient(TClient client); + + /// + /// 释放使用完成的客户端 + /// + /// + /// + public virtual Task ReleaseTransferClientAsync(TClient client) + { + return Task.Run(() => + { + this.ReleaseTransferClient(client); + }); + } + + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DisposeClient(MainClient); + this.Clear(); + } + + /// + /// 获取用于传输的客户端配置 + /// + /// + protected abstract TouchSocketConfig GetTransferConfig(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs.meta new file mode 100644 index 0000000..98dee4a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/ClientFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f3ac88ebeb1ed746ab3063563529f6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs new file mode 100644 index 0000000..1158c46 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs @@ -0,0 +1,273 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 适用于Tcp客户端的连接工厂。 + /// + /// + public class TcpClientFactory : ClientFactory where TClient : ITcpClient, new() + { + private readonly TClient m_mainClient = new TClient(); + + private readonly SingleTimer m_singleTimer; + + private bool first = true; + + /// + /// 适用于Tcp客户端的连接工厂。 + /// + public TcpClientFactory() + { + m_singleTimer = new SingleTimer(1000, () => + { + List list = new List(); + foreach (var item in this.CreatedClients) + { + if (!this.IsAlive(item)) + { + list.Add(item); + } + } + + foreach (var item in list) + { + this.DisposeClient(item); + } + + if (IsAlive(this.MainClient)) + { + if (this.CreatedClients.Count < this.MinCount) + { + try + { + this.CreateTransferClient(); + } + catch + { + } + } + } + }); + } + + /// + /// 连接超时设定 + /// + public TimeSpan ConnectTimeout { get; set; } = TimeSpan.FromSeconds(5); + + /// + public override TClient MainClient { get => m_mainClient; } + + /// + /// 获取传输的客户端配置 + /// + public Func OnGetTransferConfig { get; set; } + + /// + public override Result CheckStatus(bool tryInit = true) + { + lock (this.m_singleTimer) + { + try + { + if (!IsAlive(m_mainClient)) + { + if (!tryInit) + { + return Result.UnknownFail; + } + if (first) + { + OnMainClientSetuping(); + MainClient.Setup(this.MainConfig); + first = false; + } + MainClient.Close(); + MainClient.Connect((int)this.ConnectTimeout.TotalMilliseconds); + } + return Result.Success; + } + catch (Exception ex) + { + return new Result(ex); + } + } + } + + /// + /// 在主客户端加载配置之前 + /// + protected virtual void OnMainClientSetuping() + { + + } + + /// + public override void DisposeClient(TClient client) + { + client.TryShutdown(); + client.SafeDispose(); + this.CreatedClients.Remove(client); + } + + /// + /// 获取可以使用的客户端数量。 + /// + /// 注意:该值不一定是的长度,当已创建数量小于设定的最大值时,也会累加未创建的值。 + /// + /// + /// + public override int GetAvailableCount() + { + return Math.Max(0, this.MaxCount - this.CreatedClients.Count) + this.FreeClients.Count; + } + + /// + /// 获取一个空闲的连接对象,如果等待超出设定的时间,则会创建新的连接。 + /// + /// 指定毫秒数 + /// + /// + /// + public TClient GetTransferClient(int waitTime) + { + return this.GetTransferClient(TimeSpan.FromMilliseconds(waitTime)); + } + + /// + /// 获取一个空闲的连接对象,如果等待超出1秒的时间,则会创建新的连接。 + /// + /// + /// + /// + public TClient GetTransferClient() + { + return this.GetTransferClient(TimeSpan.FromSeconds(1)); + } + + /// + /// 获取一个空闲的连接对象,如果等待超出设定的时间,则会创建新的连接。 + /// + /// + /// + /// + /// + public override TClient GetTransferClient(TimeSpan waitTime) + { + while (FreeClients.TryDequeue(out var client)) + { + if (IsAlive(client)) + { + return client; + } + else + { + DisposeClient(client); + } + } + + if (this.CreatedClients.Count > MaxCount) + { + if (SpinWait.SpinUntil(Wait, waitTime)) + { + return GetTransferClient(waitTime); + } + } + + var clientRes = CreateTransferClient(); + return clientRes; + } + + /// + public override bool IsAlive(TClient client) + { + return client.Online; + } + + /// + /// 归还使用完的连接。 + /// + /// 首先内部会判定存活状态,如果不再活动状态,会直接调用。 + /// 其次会计算是否可以进入缓存队列,如果队列数量超出,也会直接调用 + /// + /// + /// + public override void ReleaseTransferClient(TClient client) + { + if ((object)client == (object)MainClient) + { + return; + } + if (!IsAlive(client)) + { + DisposeClient(client); + return; + } + if (FreeClients.Count < MaxCount) + { + FreeClients.Enqueue(client); + } + else + { + DisposeClient(client); + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + this.m_singleTimer.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override TouchSocketConfig GetTransferConfig() + { + return OnGetTransferConfig?.Invoke(); + } + + private TClient CreateTransferClient() + { + TClient client = new TClient(); + client.Setup(this.GetTransferConfig()); + client.Connect((int)ConnectTimeout.TotalMilliseconds); + this.CreatedClients.Add(client); + return client; + } + + private bool Wait() + { + if (FreeClients.Count > 0) + { + return true; + } + return false; + } + } + + /// + /// 适用于基于的连接工厂。 + /// + public class TcpClientFactory : TcpClientFactory + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs.meta new file mode 100644 index 0000000..99a9e73 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 116fc1f76209c9e48a9479a2815584b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT.meta new file mode 100644 index 0000000..b40cd90 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc7d9c139fb317b49ba9ac21db8469f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs new file mode 100644 index 0000000..96606ca --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP端口转发服务器 + /// + public class NATService : TcpService + { + /// + /// + /// + /// + protected override NATSocketClient GetClientInstence() + { + var client = base.GetClientInstence(); + client.m_internalDis = OnTargetClientDisconnected; + client.m_internalTargetClientRev = OnTargetClientReceived; + return client; + } + + /// + /// 在NAT服务器收到数据时。 + /// + /// + /// + /// + /// 需要转发的数据。 + protected virtual byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + return byteBlock?.ToArray(); + } + + /// + /// + /// + /// + /// + /// + protected override sealed void OnReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + var data = OnNATReceived(socketClient, byteBlock, requestInfo); + if (data != null) + { + socketClient.SendToTargetClient(data, 0, data.Length); + } + } + + /// + /// 当目标客户端断开。 + /// + /// + /// + /// + protected virtual void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, DisconnectEventArgs e) + { + } + + /// + /// 在目标客户端收到数据时。 + /// + /// + /// + /// + /// + /// + protected virtual byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + return byteBlock?.ToArray(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs.meta new file mode 100644 index 0000000..61929da --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1312656912c39c840be4fbcf051151e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs new file mode 100644 index 0000000..274716d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 端口转发辅助 + /// + public class NATSocketClient : SocketClient + { + internal Action m_internalDis; + internal Func m_internalTargetClientRev; + private readonly ConcurrentList m_targetClients = new ConcurrentList(); + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + public ITcpClient AddTargetClient(TouchSocketConfig config, Action setupAction = default) + { + TcpClient tcpClient = new TcpClient(); + tcpClient.Disconnected += TcpClient_Disconnected; + tcpClient.Received += TcpClient_Received; + tcpClient.Setup(config); + setupAction?.Invoke(tcpClient); + tcpClient.Connect(); + + m_targetClients.Add(tcpClient); + return tcpClient; + } + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + public Task AddTargetClientAsync(TouchSocketConfig config, Action setupAction = default) + { + return EasyTask.Run(() => + { + return AddTargetClient(config, setupAction); + }); + } + + /// + /// 获取所有目标客户端 + /// + /// + public ITcpClient[] GetTargetClients() + { + return m_targetClients.ToArray(); + } + + /// + /// 发送数据到全部转发端。 + /// + /// + /// + /// + public void SendToTargetClient(byte[] buffer, int offset, int length) + { + foreach (var socket in m_targetClients) + { + try + { + socket.Send(buffer, offset, length); + } + catch + { + } + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + foreach (var client in m_targetClients) + { + client.TryShutdown(); + client.SafeDispose(); + } + base.OnDisconnected(e); + } + + private void TcpClient_Disconnected(ITcpClientBase client, DisconnectEventArgs e) + { + client.Dispose(); + m_targetClients.Remove((ITcpClient)client); + m_internalDis?.Invoke(this, (ITcpClient)client, e); + } + + private void TcpClient_Received(TcpClient client, ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + + try + { + var data = m_internalTargetClientRev?.Invoke(this, client, byteBlock, requestInfo); + if (data != null) + { + if (Online) + { + this.Send(data); + } + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs.meta new file mode 100644 index 0000000..8417d05 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47c137fc2a2845b419f255790d687e86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP.meta new file mode 100644 index 0000000..3dc2398 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81d14b26829834245955b91e1df92c4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs new file mode 100644 index 0000000..1a1c592 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs @@ -0,0 +1,964 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器辅助类 + /// + [DebuggerDisplay("ID={ID},IPAdress={IP}:{Port}")] + public class SocketClient : BaseSocket, ISocketClient + { + /// + /// 构造函数 + /// + public SocketClient() + { + Protocol = Protocol.TCP; + } + + #region 变量 + + internal string m_id; + internal ReceiveType m_receiveType; + internal TcpServiceBase m_service; + internal bool m_usePlugin; + private DataHandlingAdapter m_adapter; + private DelaySender m_delaySender; + private Socket m_mainSocket; + + //private int m_maxPackageSize; + private bool m_online; + + private bool m_useDelaySender; + private Stream m_workStream; + + #endregion 变量 + + #region 属性 + + /// + public bool IsClient => false; + + /// + /// + /// + public bool CanSend => m_online; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// + /// + public TouchSocketConfig Config { get; internal set; } + + /// + /// + /// + public IContainer Container => Config?.Container; + + /// + /// + /// + public DataHandlingAdapter DataHandlingAdapter => m_adapter; + + /// + /// 用于索引的ID + /// + public string ID => m_id; + + /// + /// + /// + public string IP { get; private set; } + + /// + /// + /// + public Socket MainSocket => m_mainSocket; + + /// + /// + /// + public bool Online => m_online; + + /// + /// + /// + public IPluginsManager PluginsManager => Config?.PluginsManager; + + /// + /// + /// + public int Port { get; private set; } + + /// + /// + /// + public Protocol Protocol { get; set; } + + /// + /// + /// + public ReceiveType ReceiveType => m_receiveType; + + /// + /// + /// + public TcpServiceBase Service => m_service; + + /// + /// + /// + public bool UsePlugin => m_usePlugin; + + /// + /// + /// + public bool UseSsl { get; private set; } + + #endregion 属性 + + #region 事件&委托 + + /// + /// + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + protected virtual void OnDisconnecting(DisconnectEventArgs e) + { + try + { + Disconnecting?.Invoke(this, e); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(Disconnecting)}中发生错误。", ex); + } + } + /// + /// 当客户端完整建立TCP连接,如果覆盖父类方法,则不会触发插件。 + /// + /// + protected virtual void OnConnected(TouchSocketEventArgs e) + { + m_service.OnInternalConnected(this, e); + } + + /// + /// 客户端正在连接,如果覆盖父类方法,则不会触发插件。 + /// + protected virtual void OnConnecting(OperationEventArgs e) + { + m_service.OnInternalConnecting(this, e); + } + + /// + /// 在延迟发生错误 + /// + /// + protected virtual void OnDelaySenderError(Exception ex) + { + Logger.Log(LogType.Error, this, "发送错误", ex); + } + + /// + /// 客户端已断开连接,如果从Connecting中拒绝连接,则不会触发。如果覆盖父类方法,则不会触发插件。 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + Disconnected?.Invoke(this, e); + } + + /// + /// 当初始化完成时,执行在之前。 + /// + protected virtual void OnInitialized() + { + } + + private void PrivateOnDisconnected(DisconnectEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(IDisconnectedPlguin.OnDisconnected), this, e)) + { + return; + } + OnDisconnected(e); + if (!e.Handled) + { + m_service.OnInternalDisconnected(this, e); + } + } + + private void PrivateOnDisconnecting(DisconnectEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(IDisconnectingPlugin.OnDisconnecting), this, e)) + { + return; + } + OnDisconnecting(e); + if (!e.Handled) + { + m_service.OnInternalDisconnecting(this, e); + } + } + #endregion 事件&委托 + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public string ServiceIP { get; private set; } + + /// + /// + /// + public int ServicePort { get; private set; } + + /// + public virtual void Close() + { + Close($"主动调用{nameof(Close)}"); + } + + /// + public virtual void Close(string msg) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, msg) + { + IsPermitOperation = true + }; + PrivateOnDisconnecting(args); + if (this.DisposedValue || args.IsPermitOperation) + { + BreakOut(msg, true); + } + } + } + + /// + /// + /// + /// + public Stream GetStream() + { + if (m_workStream == null) + { + m_workStream = new NetworkStream(m_mainSocket, true); + } + return m_workStream; + } + + /// + /// 直接重置内部ID。 + /// + /// + protected void DirectResetID(string newId) + { + if (string.IsNullOrEmpty(newId)) + { + throw new ArgumentException($"“{nameof(newId)}”不能为 null 或空。", nameof(newId)); + } + + if (m_id == newId) + { + return; + } + string oldId = m_id; + if (Service.SocketClients.TryRemove(m_id, out SocketClient socketClient)) + { + socketClient.m_id = newId; + if (Service.SocketClients.TryAdd(socketClient)) + { + if (m_usePlugin) + { + IDChangedEventArgs e = new IDChangedEventArgs(oldId, newId); + PluginsManager.Raise(nameof(ITcpPlugin.OnIDChanged), socketClient, e); + } + return; + } + else + { + socketClient.m_id = oldId; + if (Service.SocketClients.TryAdd(socketClient)) + { + throw new Exception("ID重复"); + } + else + { + socketClient.Close("修改新ID时操作失败,且回退旧ID时也失败。"); + } + } + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldId)); + } + } + + /// + /// + /// + /// + /// + /// + /// + public virtual void ResetID(string newId) + { + DirectResetID(newId); + } + + /// + /// + /// + /// + public virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (!CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + SetAdapter(adapter); + } + + internal void BeginReceive(ReceiveType receiveType) + { + try + { + if (receiveType == ReceiveType.Auto) + { + SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); + eventArgs.Completed += EventArgs_Completed; + ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength); + eventArgs.UserToken = byteBlock; + eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + if (!m_mainSocket.ReceiveAsync(eventArgs)) + { + ProcessReceived(eventArgs); + } + } + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + + internal void BeginReceiveSsl(ReceiveType receiveType, ServiceSslOption sslOption) + { + SslStream sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(m_mainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(m_mainSocket, false), false); + sslStream.AuthenticateAsServer(sslOption.Certificate, sslOption.ClientCertificateRequired, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); + m_workStream = sslStream; + UseSsl = true; + if (receiveType == ReceiveType.Auto) + { + BeginSsl(); + } + } + + internal void InternalConnected(TouchSocketEventArgs e) + { + m_online = true; + + if (Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + m_useDelaySender = true; + m_delaySender.SafeDispose(); + m_delaySender = new DelaySender(m_mainSocket, senderOption.QueueLength, OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + if (m_usePlugin && PluginsManager.Raise(nameof(IConnectedPlugin.OnConnected), this, e)) + { + return; + } + + OnConnected(e); + } + + internal void InternalConnecting(OperationEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(IConnectingPlugin.OnConnecting), this, e)) + { + return; + } + OnConnecting(e); + } + + internal void InternalInitialized() + { + LastReceivedTime = DateTime.Now; + LastSendTime = DateTime.Now; + OnInitialized(); + } + + internal void SetSocket(Socket mainSocket) + { + m_mainSocket = mainSocket ?? throw new ArgumentNullException(nameof(mainSocket)); + IP = mainSocket.RemoteEndPoint.GetIP(); + Port = mainSocket.RemoteEndPoint.GetPort(); + ServiceIP = mainSocket.LocalEndPoint.GetIP(); + ServicePort = mainSocket.LocalEndPoint.GetPort(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"); + PrivateOnDisconnecting(args); + } + m_adapter.SafeDispose(); + m_adapter = default; + BreakOut($"{nameof(Dispose)}主动断开", true); + base.Dispose(disposing); + } + + /// + /// 处理已接收到的数据。 + /// 根据不同的数据处理适配器,会传递不同的数据 + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(byte[] buffer, int offset, int length) + { + if (m_usePlugin) + { + SendingEventArgs args = new SendingEventArgs(buffer, offset, length); + PluginsManager.Raise(nameof(ITcpPlugin.OnSendingData), this, args); + if (args.IsPermitOperation) + { + return true; + } + return false; + } + return true; + } + + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(DataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (Config != null) + { + if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty) != TimeSpan.Zero) + { + adapter.CacheTimeout = Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty); + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutEnableProperty) is bool v2) + { + adapter.CacheTimeoutEnable = v2; + } + if (Config.GetValue(TouchSocketConfigExtension.UpdateCacheTimeWhenRevProperty) is bool v3) + { + adapter.UpdateCacheTimeWhenRev = v3; + } + } + + adapter.OnLoaded(this); + adapter.ReceivedCallBack = PrivateHandleReceivedData; + adapter.SendCallBack = DefaultSend; + m_adapter = adapter; + } + + private void BeginSsl() + { + if (!DisposedValue) + { + ByteBlock byteBlock = new ByteBlock(BufferLength); + try + { + m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, EndSsl, byteBlock); + } + catch (System.Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + } + + private void BreakOut(string msg, bool manual) + { + lock (this.SyncRoot) + { + if (m_online) + { + m_online = false; + this.TryShutdown(); + m_mainSocket.SafeDispose(); + m_delaySender.SafeDispose(); + m_adapter.SafeDispose(); + m_service?.SocketClients.TryRemove(m_id, out _); + PrivateOnDisconnected(new DisconnectEventArgs(manual, msg)); + Disconnected = null; + } + base.Dispose(true); + } + } + + private void EndSsl(IAsyncResult result) + { + ByteBlock byteBlock = (ByteBlock)result.AsyncState; + try + { + int r = m_workStream.EndRead(result); + if (r == 0) + { + BreakOut("远程终端主动关闭", false); + } + byteBlock.SetLength(r); + + HandleBuffer(byteBlock); + BeginSsl(); + } + catch (Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + ProcessReceived(e); + } + catch (Exception ex) + { + e.SafeDispose(); + BreakOut(ex.Message, false); + } + } + + private void HandleBuffer(ByteBlock byteBlock) + { + try + { + LastReceivedTime = DateTime.Now; + if (OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnReceivingData), this, new ByteBlockEventArgs(byteBlock))) + { + return; + } + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + m_adapter.ReceivedInput(byteBlock); + } + catch (System.Exception ex) + { + Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + + if (m_usePlugin) + { + ReceivedDataEventArgs args = new ReceivedDataEventArgs(byteBlock, requestInfo); + PluginsManager.Raise(nameof(ITcpPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + + HandleReceivedData(byteBlock, requestInfo); + + m_service.OnInternalReceivedData(this, byteBlock, requestInfo); + } + + + private void ProcessReceived(SocketAsyncEventArgs e) + { + if (DisposedValue) + { + e.SafeDispose(); + } + else + { + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + HandleBuffer(byteBlock); + try + { + ByteBlock newByteBlock = new ByteBlock(BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity); + + if (!m_mainSocket.ReceiveAsync(e)) + { + ProcessReceived(e); + } + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + else + { + e.SafeDispose(); + BreakOut("远程主机主动断开连接", false); + } + } + } + + #region 发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + if (!m_online) + { + throw new NotConnectedException(TouchSocketStatus.NotConnected.GetDescription()); + } + if (HandleSendingData(buffer, offset, length)) + { + if (UseSsl) + { + m_workStream.Write(buffer, offset, length); + } + else + { + if (m_useDelaySender && length < TouchSocketUtility.BigDataBoundary) + { + m_delaySender.Send(new QueueDataBytes(buffer, offset, length)); + } + else + { + m_mainSocket.AbsoluteSend(buffer, offset, length); + } + } + LastSendTime = DateTime.Now; + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + #region 同步发送 + + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!m_adapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + m_adapter.SendInput(requestInfo); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + m_adapter.SendInput(buffer, offset, length); + } + + /// + /// + /// + /// + public virtual void Send(IList> transferBytes) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (m_adapter.CanSplicingSend) + { + m_adapter.SendInput(transferBytes); + } + else + { + ByteBlock byteBlock = new ByteBlock(BufferLength); + try + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + m_adapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + Send(requestInfo); + }); + } + + /// + /// + /// + /// + public virtual Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(transferBytes); + }); + } + + #endregion 异步发送 + + #region ID发送 + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public void Send(string id, byte[] buffer, int offset, int length) + { + m_service.Send(id, buffer, offset, length); + } + + /// + /// + /// + /// + /// + public void Send(string id, IRequestInfo requestInfo) + { + m_service.Send(id, requestInfo); + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(string id, byte[] buffer, int offset, int length) + { + return m_service.SendAsync(id, buffer, offset, length); + } + + /// + /// + /// + /// + /// + public Task SendAsync(string id, IRequestInfo requestInfo) + { + return m_service.SendAsync(id, requestInfo); + } + + #endregion ID发送 + + #endregion 发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs.meta new file mode 100644 index 0000000..24c1761 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/SocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65131b74b64915546b4e3fe236f8c59a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs new file mode 100644 index 0000000..f81af45 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs @@ -0,0 +1,1086 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 简单TCP客户端 + /// + public class TcpClient : TcpClientBase + { + /// + /// 接收到数据 + /// + public ReceivedEventHandler Received { get; set; } + + /// + /// 接收数据 + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + this.Received?.Invoke(this, byteBlock, requestInfo); + base.HandleReceivedData(byteBlock, requestInfo); + } + } + + /// + /// TCP客户端 + /// + [System.Diagnostics.DebuggerDisplay("{IP}:{Port}")] + public class TcpClientBase : BaseSocket, ITcpClient + { + /// + /// 构造函数 + /// + public TcpClientBase() + { + this.Protocol = Protocol.TCP; + } + + #region 变量 + + private DelaySender m_delaySender; + private bool m_useDelaySender; + private Stream m_workStream; + + #endregion 变量 + + #region 事件 + + /// + /// 成功连接到服务器 + /// + public MessageEventHandler Connected { get; set; } + + /// + /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接 + /// + public ConnectingEventHandler Connecting { get; set; } + + /// + /// 断开连接。在客户端未设置连接状态时,不会触发 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + private void PrivateOnConnected(MsgEventArgs e) + { + if (this.UsePlugin) + { + this.PluginsManager.Raise(nameof(IConnectedPlugin.OnConnected), this, e); + if (e.Handled) + { + return; + } + } + this.OnConnected(e); + } + + /// + /// 已经建立Tcp连接 + /// + /// + protected virtual void OnConnected(MsgEventArgs e) + { + try + { + this.Connected?.Invoke(this, e); + } + catch (System.Exception ex) + { + this.Logger.Log(LogType.Error, this, $"在事件{nameof(this.Connected)}中发生错误。", ex); + } + } + + private void PrivateOnConnecting(ConnectingEventArgs e) + { + this.LastReceivedTime = DateTime.Now; + this.LastSendTime = DateTime.Now; + if (this.CanSetDataHandlingAdapter) + { + this.SetDataHandlingAdapter(this.Config.GetValue>(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke()); + } + if (this.UsePlugin) + { + this.PluginsManager.Raise(nameof(IConnectingPlugin.OnConnecting), this, e); + if (e.Handled) + { + return; + } + } + this.OnConnecting(e); + } + + /// + /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接 + /// + /// + protected virtual void OnConnecting(ConnectingEventArgs e) + { + try + { + this.Connecting?.Invoke(this, e); + } + catch (Exception ex) + { + this.Logger.Log(LogType.Error, this, $"在事件{nameof(this.OnConnecting)}中发生错误。", ex); + } + } + + private void PrivateOnDisconnected(DisconnectEventArgs e) + { + if (this.UsePlugin && this.PluginsManager.Raise(nameof(IDisconnectedPlguin.OnDisconnected), this, e)) + { + return; + } + this.OnDisconnected(e); + } + + /// + /// 断开连接。在客户端未设置连接状态时,不会触发 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + try + { + this.Disconnected?.Invoke(this, e); + } + catch (Exception ex) + { + this.Logger.Log(LogType.Error, this, $"在事件{nameof(this.Disconnected)}中发生错误。", ex); + } + } + + private void PrivateOnDisconnecting(DisconnectEventArgs e) + { + if (this.UsePlugin && this.PluginsManager.Raise(nameof(IDisconnectingPlugin.OnDisconnecting), this, e)) + { + return; + } + this.OnDisconnecting(e); + } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + protected virtual void OnDisconnecting(DisconnectEventArgs e) + { + try + { + this.Disconnecting?.Invoke(this, e); + } + catch (Exception ex) + { + this.Logger.Log(LogType.Error, this, $"在事件{nameof(this.Disconnecting)}中发生错误。", ex); + } + } + + #endregion 事件 + + #region 属性 + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public IContainer Container => this.Config?.Container; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// 客户端配置 + /// + public TouchSocketConfig Config { get; private set; } + + /// + /// 数据处理适配器 + /// + public DataHandlingAdapter DataHandlingAdapter { get; private set; } + + /// + /// IP地址 + /// + public string IP { get; private set; } + + /// + /// 主通信器 + /// + public Socket MainSocket { get; private set; } + + /// + /// + /// + public bool CanSend { get; private set; } + + /// + /// + /// + public bool Online => this.CanSend; + + /// + /// + /// + public IPluginsManager PluginsManager { get; private set; } + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// + /// + public ReceiveType ReceiveType { get; private set; } + + /// + /// 是否已启用插件 + /// + public bool UsePlugin { get; private set; } + + /// + /// + /// + public bool UseSsl { get; private set; } + + /// + /// + /// + public Protocol Protocol { get; set; } + + /// + /// + /// + public IPHost RemoteIPHost { get; private set; } + + /// + public bool IsClient => true; + + #endregion 属性 + + #region 断开操作 + + /// + /// + /// + public virtual void Close() + { + this.Close($"{nameof(Close)}主动断开"); + } + + /// + /// 中断终端,传递中断消息。 + /// + /// + public virtual void Close(string msg) + { + if (this.CanSend) + { + var args = new DisconnectEventArgs(true, msg) + { + IsPermitOperation = true + }; + this.PrivateOnDisconnecting(args); + if (this.DisposedValue || args.IsPermitOperation) + { + this.BreakOut(msg, true); + } + } + } + + private void BreakOut(string msg, bool manual) + { + lock (this.SyncRoot) + { + if (this.CanSend) + { + this.CanSend = false; + this.TryShutdown(); + this.MainSocket.SafeDispose(); + this.m_delaySender.SafeDispose(); + this.m_workStream.SafeDispose(); + this.DataHandlingAdapter.SafeDispose(); + this.PrivateOnDisconnected(new DisconnectEventArgs(manual, msg)); + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.CanSend) + { + var args = new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"); + this.PrivateOnDisconnecting(args); + } + this.PluginsManager?.Clear(); + this.Config = default; + this.DataHandlingAdapter.SafeDispose(); + this.DataHandlingAdapter = default; + this.BreakOut($"{nameof(Dispose)}主动断开", true); + base.Dispose(disposing); + } + + #endregion 断开操作 + + /// + /// 建立Tcp的连接。 + /// + /// + /// + /// + /// + /// + protected void TcpConnect(int timeout) + { + lock (this.SyncRoot) + { + if (this.CanSend) + { + return; + } + if (this.DisposedValue) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + if (this.Config == null) + { + throw new ArgumentNullException("配置文件不能为空。"); + } + IPHost iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + if (iPHost == null) + { + throw new ArgumentNullException("iPHost不能为空。"); + } + if (this.MainSocket != null) + { + this.MainSocket.Dispose(); + } + this.MainSocket = this.CreateSocket(iPHost); + + ConnectingEventArgs args = new ConnectingEventArgs(this.MainSocket); + this.PrivateOnConnecting(args); + if (timeout == 5000) + { + this.MainSocket.Connect(iPHost.EndPoint); + this.CanSend = true; + this.LoadSocketAndReadIpPort(); + + if (this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + this.m_useDelaySender = true; + this.m_delaySender.SafeDispose(); + this.m_delaySender = new DelaySender(this.MainSocket, senderOption.QueueLength, this.OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + this.BeginReceive(); + this.PrivateOnConnected(new MsgEventArgs("连接成功")); + } + else + { + var result = this.MainSocket.BeginConnect(iPHost.EndPoint, null, null); + if (result.AsyncWaitHandle.WaitOne(timeout)) + { + if (this.MainSocket.Connected) + { + this.MainSocket.EndConnect(result); + this.CanSend = true; + this.LoadSocketAndReadIpPort(); + + if (this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + this.m_useDelaySender = true; + this.m_delaySender.SafeDispose(); + this.m_delaySender = new DelaySender(this.MainSocket, senderOption.QueueLength, this.OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + this.BeginReceive(); + this.PrivateOnConnected(new MsgEventArgs("连接成功")); + return; + } + else + { + this.MainSocket.SafeDispose(); + throw new Exception("异步已完成,但是socket并未在连接状态,可能发生了绑定端口占用的错误。"); + } + } + this.MainSocket.SafeDispose(); + throw new TimeoutException(); + } + } + } + + /// + /// 请求连接到服务器。 + /// + public virtual ITcpClient Connect(int timeout = 5000) + { + this.TcpConnect(timeout); + return this; + } + + /// + /// 异步连接服务器 + /// + public Task ConnectAsync(int timeout = 5000) + { + return EasyTask.Run(() => + { + return this.Connect(timeout); + }); + } + + /// + /// + /// + /// + public Stream GetStream() + { + if (this.m_workStream == null) + { + this.m_workStream = new NetworkStream(this.MainSocket, true); + } + return this.m_workStream; + } + + /// + /// 设置数据处理适配器 + /// + /// + public virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (!this.CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + this.SetAdapter(adapter); + } + + /// + /// + /// + /// + /// + public ITcpClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return this.Setup(config); + } + + /// + /// 配置服务器 + /// + /// + /// + public ITcpClient Setup(TouchSocketConfig config) + { + this.Config = config; + this.PluginsManager = config.PluginsManager; + + if (config.IsUsePlugin) + { + this.PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + this.LoadConfig(this.Config); + if (this.UsePlugin) + { + this.PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + return this; + } + + private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + if (this.UsePlugin) + { + ReceivedDataEventArgs args = new ReceivedDataEventArgs(byteBlock, requestInfo); + this.PluginsManager.Raise(nameof(ITcpPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + + this.HandleReceivedData(byteBlock, requestInfo); + } + + /// + /// 处理已接收到的数据。 + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(byte[] buffer, int offset, int length) + { + if (this.UsePlugin) + { + SendingEventArgs args = new SendingEventArgs(buffer, offset, length); + this.PluginsManager.Raise(nameof(ITcpPlugin.OnSendingData), this, args); + if (args.IsPermitOperation) + { + return true; + } + return false; + } + return true; + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + this.BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + this.ReceiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty); + this.UsePlugin = config.IsUsePlugin; + this.Logger = this.Container.Resolve(); + + if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null) + { + this.UseSsl = true; + } + } + + /// + /// 在延迟发生错误 + /// + /// + protected virtual void OnDelaySenderError(Exception ex) + { + this.Logger.Log(LogType.Error, this, "发送错误", ex); + } + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(DataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (this.Config != null) + { + if (this.Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + if (this.Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty) != TimeSpan.Zero) + { + adapter.CacheTimeout = this.Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty); + } + if (this.Config.GetValue(TouchSocketConfigExtension.CacheTimeoutEnableProperty) is bool v2) + { + adapter.CacheTimeoutEnable = v2; + } + if (this.Config.GetValue(TouchSocketConfigExtension.UpdateCacheTimeWhenRevProperty) is bool v3) + { + adapter.UpdateCacheTimeWhenRev = v3; + } + } + + adapter.OnLoaded(this); + adapter.ReceivedCallBack = this.PrivateHandleReceivedData; + adapter.SendCallBack = this.DefaultSend; + this.DataHandlingAdapter = adapter; + } + + private void BeginReceive() + { + this.m_workStream.SafeDispose(); + if (this.UseSsl) + { + ClientSslOption sslOption = (ClientSslOption)this.Config.GetValue(TouchSocketConfigExtension.SslOptionProperty); + SslStream sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.MainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.MainSocket, false), false); + if (sslOption.ClientCertificates == null) + { + sslStream.AuthenticateAsClient(sslOption.TargetHost); + } + else + { + sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); + } + this.m_workStream = sslStream; + if (this.ReceiveType != ReceiveType.None) + { + this.BeginSsl(); + } + } + else + { + if (this.ReceiveType == ReceiveType.Auto) + { + SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); + eventArgs.Completed += this.EventArgs_Completed; + + ByteBlock byteBlock = BytePool.Default.GetByteBlock(this.BufferLength); + eventArgs.UserToken = byteBlock; + eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Buffer.Length); + if (!this.MainSocket.ReceiveAsync(eventArgs)) + { + this.ProcessReceived(eventArgs); + } + } + } + } + + private void BeginSsl() + { + ByteBlock byteBlock = new ByteBlock(this.BufferLength); + try + { + this.m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, this.EndSsl, byteBlock); + } + catch (Exception ex) + { + byteBlock.Dispose(); + this.BreakOut(ex.Message, false); + } + } + + private void EndSsl(IAsyncResult result) + { + ByteBlock byteBlock = (ByteBlock)result.AsyncState; + try + { + int r = this.m_workStream.EndRead(result); + if (r == 0) + { + this.BreakOut("远程终端主动关闭", false); + } + byteBlock.SetLength(r); + this.HandleBuffer(byteBlock); + this.BeginSsl(); + } + catch (System.Exception ex) + { + byteBlock.Dispose(); + this.BreakOut(ex.Message, false); + } + } + + private Socket CreateSocket(IPHost iPHost) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + socket.ReceiveBufferSize = this.BufferLength; + socket.SendBufferSize = this.BufferLength; +#if NET45_OR_GREATER + KeepAliveValue keepAliveValue = this.Config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty); + if (keepAliveValue.Enable) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null); + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + KeepAliveValue keepAliveValue = Config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty); + if (keepAliveValue.Enable) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null); + } + } +#endif + socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, this.Config.GetValue(TouchSocketConfigExtension.NoDelayProperty)); + if (this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) != null) + { + if (this.Config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + socket.Bind(this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty).EndPoint); + } + return socket; + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + this.ProcessReceived(e); + } + catch (System.Exception ex) + { + e.Dispose(); + this.BreakOut(ex.Message, false); + } + } + + /// + /// 处理数据 + /// + private void HandleBuffer(ByteBlock byteBlock) + { + try + { + this.LastReceivedTime = DateTime.Now; + if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (this.DisposedValue) + { + return; + } + if (this.UsePlugin && this.PluginsManager.Raise(nameof(ITcpPlugin.OnReceivingData), this, new ByteBlockEventArgs(byteBlock))) + { + return; + } + if (this.DataHandlingAdapter == null) + { + this.Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + this.DataHandlingAdapter.ReceivedInput(byteBlock); + } + catch (Exception ex) + { + this.Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + #region 发送 + + #region 同步发送 + + /// + /// + /// + /// + /// + /// + /// + public void Send(IRequestInfo requestInfo) + { + if (this.DisposedValue) + { + return; + } + if (this.DataHandlingAdapter == null) + { + throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!this.DataHandlingAdapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + this.DataHandlingAdapter.SendInput(requestInfo); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (this.DataHandlingAdapter == null) + { + throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + this.DataHandlingAdapter.SendInput(buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(IList> transferBytes) + { + if (this.DataHandlingAdapter == null) + { + throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + + if (this.DataHandlingAdapter.CanSplicingSend) + { + this.DataHandlingAdapter.SendInput(transferBytes); + } + else + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(this.BufferLength); + try + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + this.Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + this.Send(requestInfo); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + this.Send(transferBytes); + }); + } + + #endregion 异步发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + if (!this.CanSend) + { + throw new NotConnectedException(TouchSocketStatus.NotConnected.GetDescription()); + } + if (this.HandleSendingData(buffer, offset, length)) + { + if (this.UseSsl) + { + this.m_workStream.Write(buffer, offset, length); + } + else + { + if (this.m_useDelaySender && length < TouchSocketUtility.BigDataBoundary) + { + this.m_delaySender.Send(new QueueDataBytes(buffer, offset, length)); + } + else + { + this.MainSocket.AbsoluteSend(buffer, offset, length); + } + } + + this.LastSendTime = DateTime.Now; + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + this.DefaultSend(buffer, offset, length); + }); + } + + #endregion 发送 + + private void LoadSocketAndReadIpPort() + { + if (this.MainSocket == null) + { + this.IP = null; + this.Port = -1; + return; + } + + string ipport; + if (this.MainSocket.Connected && this.MainSocket.RemoteEndPoint != null) + { + ipport = this.MainSocket.RemoteEndPoint.ToString(); + } + else if (this.MainSocket.IsBound && this.MainSocket.LocalEndPoint != null) + { + ipport = this.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 ProcessReceived(SocketAsyncEventArgs e) + { + if (!this.CanSend) + { + e.Dispose(); + return; + } + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + this.HandleBuffer(byteBlock); + try + { + ByteBlock newByteBlock = BytePool.Default.GetByteBlock(this.BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + if (!this.MainSocket.ReceiveAsync(e)) + { + this.ProcessReceived(e); + } + } + catch (System.Exception ex) + { + e.Dispose(); + this.BreakOut(ex.Message, false); + } + } + else + { + e.Dispose(); + this.BreakOut("远程终端主动关闭", false); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs.meta new file mode 100644 index 0000000..fa6359e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64c56289afb667c47a0bc285376490ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs new file mode 100644 index 0000000..b68d656 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// TCP泛型服务器,由客户自己指定类型。 + /// + public class TcpService : TcpServiceBase, ITcpService where TClient : SocketClient + { + /// + /// 构造函数 + /// + public TcpService() + { + m_socketClients = new SocketClientCollection(); + m_getDefaultNewID = () => + { + return Interlocked.Increment(ref m_nextId).ToString(); + }; + } + + #region 变量 + + private readonly SocketClientCollection m_socketClients; + private int m_backlog; + private TouchSocketConfig m_config; + private Func m_getDefaultNewID; + private int m_maxCount; + private NetworkMonitor[] m_monitors; + private long m_nextId; + private ReceiveType m_receiveType; + private ServerState m_serverState; + private bool m_usePlugin; + private bool m_useSsl; + + #endregion 变量 + + #region 属性 + + /// + /// 获取服务器配置 + /// + public override TouchSocketConfig Config => m_config; + + /// + /// + /// + public override IContainer Container => Config?.Container; + + /// + /// + /// + public override Func GetDefaultNewID => m_getDefaultNewID; + + /// + /// + /// + public override int MaxCount => m_maxCount; + + /// + /// + /// + public override NetworkMonitor[] Monitors => m_monitors; + + /// + /// + /// + public override IPluginsManager PluginsManager => Config?.PluginsManager; + + /// + /// + /// + public override string ServerName => Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty); + + /// + /// + /// + public override ServerState ServerState => m_serverState; + + /// + /// + /// + public override SocketClientCollection SocketClients => m_socketClients; + + /// + /// + /// + public override bool UsePlugin => m_usePlugin; + + /// + /// + /// + public override bool UseSsl => m_useSsl; + + #endregion 属性 + + #region 事件 + + /// + /// 用户连接完成 + /// + public TouchSocketEventHandler Connected { get; set; } + + /// + /// 有用户连接的时候 + /// + public OperationEventHandler Connecting { get; set; } + + /// + /// 有用户断开连接 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + /// + /// 当客户端ID被修改时触发。 + /// + public IDChangedEventHandler IDChanged { get; set; } + + /// + /// + /// + /// + /// + protected override sealed void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e) + { + OnConnected((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e) + { + OnConnecting((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e) + { + OnDisconnected((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e) + { + OnDisconnecting((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + /// + protected override sealed void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + OnReceived((TClient)socketClient, byteBlock, requestInfo); + } + + /// + /// 客户端连接完成,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnConnected(TClient socketClient, TouchSocketEventArgs e) + { + Connected?.Invoke(socketClient, e); + } + + /// + /// 客户端请求连接,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnConnecting(TClient socketClient, OperationEventArgs e) + { + Connecting?.Invoke(socketClient, e); + } + + /// + /// 客户端断开连接,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnDisconnected(TClient socketClient, DisconnectEventArgs e) + { + Disconnected?.Invoke(socketClient, e); + } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + protected virtual void OnDisconnecting(TClient socketClient, DisconnectEventArgs e) + { + Disconnecting?.Invoke(socketClient, e); + } + + /// + /// 当收到适配器数据。 + /// + /// + /// + /// + protected virtual void OnReceived(TClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + #endregion 事件 + + /// + /// + /// + public override void Clear() + { + string[] ids = GetIDs(); + foreach (var item in ids) + { + if (TryGetSocketClient(item, out TClient client)) + { + client.Dispose(); + } + } + } + + /// + /// 获取当前在线的所有客户端 + /// + /// + public TClient[] GetClients() + { + var clients = m_socketClients.GetClients().ToArray(); + + TClient[] clients1 = new TClient[clients.Length]; + for (int i = 0; i < clients.Length; i++) + { + clients1[i] = (TClient)clients[i]; + } + return clients1; + } + + /// + /// + /// + /// + /// + /// + /// + public override void ResetID(string oldID, string newID) + { + if (string.IsNullOrEmpty(oldID)) + { + throw new ArgumentException($"“{nameof(oldID)}”不能为 null 或空。", nameof(oldID)); + } + + if (string.IsNullOrEmpty(newID)) + { + throw new ArgumentException($"“{nameof(newID)}”不能为 null 或空。", nameof(newID)); + } + + if (oldID == newID) + { + return; + } + if (m_socketClients.TryGetSocketClient(oldID, out TClient socketClient)) + { + socketClient.ResetID(newID); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldID)); + } + } + + /// + /// + /// + /// + public override IService Setup(TouchSocketConfig config) + { + m_config = config; + if (config.IsUsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + LoadConfig(m_config); + if (UsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + Container.RegisterTransient(); + return this; + } + + /// + /// + /// + /// + public override IService Setup(int port) + { + TouchSocketConfig serviceConfig = new TouchSocketConfig(); + serviceConfig.SetListenIPHosts(new IPHost[] { new IPHost(port) }); + return Setup(serviceConfig); + } + + /// + /// + /// + /// + /// + public override bool SocketClientExist(string id) + { + return SocketClients.SocketClientExist(id); + } + + /// + /// + /// + /// + /// + /// + public override IService Start() + { + try + { + IPHost[] iPHosts = Config.GetValue(TouchSocketConfigExtension.ListenIPHostsProperty); + if (iPHosts == null || iPHosts.Length == 0) + { + throw new Exception("IPHosts为空,无法绑定"); + } + switch (m_serverState) + { + case ServerState.None: + { + BeginListen(iPHosts); + break; + } + case ServerState.Running: + { + return this; + } + case ServerState.Stopped: + { + BeginListen(iPHosts); + break; + } + case ServerState.Disposed: + { + throw new Exception("无法重新利用已释放对象"); + } + } + m_serverState = ServerState.Running; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + catch (Exception ex) + { + m_serverState = ServerState.Exception; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message=ex.Message }); + } + throw; + } + } + + /// + /// + /// + public override IService Stop() + { + if (m_monitors != null) + { + foreach (var item in m_monitors) + { + item.Socket?.Dispose(); + } + } + m_monitors = null; + + Clear(); + + m_serverState = ServerState.Stopped; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + public bool TryGetSocketClient(string id, out TClient socketClient) + { + return m_socketClients.TryGetSocketClient(id, out socketClient); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue) + { + if (disposing) + { + if (m_monitors != null) + { + foreach (var item in m_monitors) + { + item.Socket?.Dispose(); + } + m_monitors = null; + } + Clear(); + m_serverState = ServerState.Disposed; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + PluginsManager.Clear(); + } + } + + base.Dispose(disposing); + } + + /// + /// 初始化客户端实例,默认实现为 + /// + /// + protected virtual TClient GetClientInstence() + { + return Container.Resolve(); + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIDProperty) is Func fun) + { + m_getDefaultNewID = fun; + } + m_usePlugin = config.IsUsePlugin; + m_maxCount = config.GetValue(TouchSocketConfigExtension.MaxCountProperty); + m_backlog = config.GetValue(TouchSocketConfigExtension.BacklogProperty); + BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + m_receiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty); + + Logger ??= Container.Resolve(); + if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null) + { + m_useSsl = true; + } + } + + /// + /// 在验证Ssl发送错误时。 + /// + /// + protected virtual void OnAuthenticatingError(System.Exception ex) + { + } + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + private void Args_Completed(object sender, SocketAsyncEventArgs e) + { + if (e.LastOperation == SocketAsyncOperation.Accept) + { + OnAccepted(e); + } + } + + private void BeginListen(IPHost[] iPHosts) + { + int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty); + if (threadCount > 0) + { + while (!ThreadPool.SetMinThreads(threadCount, threadCount)) + { + if (--threadCount <= 10) + { + break; + } + } + } + + List networkMonitors = new List(); + foreach (var iPHost in iPHosts) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp) + { + ReceiveBufferSize = BufferLength, + SendBufferSize = BufferLength + }; + if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + PreviewBind(socket); + socket.Bind(iPHost.EndPoint); + socket.Listen(m_backlog); + + networkMonitors.Add(new NetworkMonitor(iPHost, socket)); + } + + m_monitors = networkMonitors.ToArray(); + foreach (var networkMonitor in m_monitors) + { + SocketAsyncEventArgs e = new SocketAsyncEventArgs + { + UserToken = networkMonitor.Socket + }; + e.Completed += Args_Completed; + if (!networkMonitor.Socket.AcceptAsync(e)) + { + OnAccepted(e); + } + } + } + + private void OnAccepted(SocketAsyncEventArgs e) + { + if (!DisposedValue) + { + if (e.SocketError == SocketError.Success && e.AcceptSocket != null) + { + Socket socket = e.AcceptSocket; + socket.ReceiveBufferSize = BufferLength; + socket.SendBufferSize = BufferLength; + if (SocketClients.Count < m_maxCount) + { + SocketInit(socket); + } + else + { + socket.SafeDispose(); + Logger.Warning(this, "连接客户端数量已达到设定最大值"); + } + } + e.AcceptSocket = null; + + try + { + if (!((Socket)e.UserToken).AcceptAsync(e)) + { + OnAccepted(e); + } + } + catch + { + e.Dispose(); + return; + } + } + } + + private void SetClientConfiguration(SocketClient client) + { + client.m_usePlugin = m_usePlugin; + client.Config = m_config; + client.m_service = this; + client.Logger = Container.Resolve(); + client.m_receiveType = m_receiveType; + client.BufferLength = BufferLength; + if (client.CanSetDataHandlingAdapter) + { + client.SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke()); + } + } + + private void SocketInit(Socket socket) + { + try + { + if (Config.GetValue(TouchSocketConfigExtension.NoDelayProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + } + TClient client = GetClientInstence(); + SetClientConfiguration(client); + client.SetSocket(socket); + client.InternalInitialized(); + + OperationEventArgs args = new OperationEventArgs + { + ID = GetDefaultNewID() + }; + client.InternalConnecting(args);//Connecting + if (args.IsPermitOperation) + { + client.m_id = args.ID; + if (SocketClients.TryAdd(client)) + { + client.InternalConnected(new MsgEventArgs("客户端成功连接")); + if (!client.MainSocket.Connected) + { + return; + } + if (m_useSsl) + { + try + { + client.BeginReceiveSsl(m_receiveType, (ServiceSslOption)m_config.GetValue(TouchSocketConfigExtension.SslOptionProperty)); + } + catch (System.Exception ex) + { + OnAuthenticatingError(ex); + return; + } + } + else + { + client.BeginReceive(m_receiveType); + } + } + else + { + throw new Exception($"ID={client.m_id}重复"); + } + } + else + { + socket.SafeDispose(); + } + } + catch (Exception ex) + { + socket.SafeDispose(); + Logger.Log(LogType.Error, this, "接收新连接错误", ex); + } + } + } + + /// + /// TCP服务器 + /// + public class TcpService : TcpService + { + /// + /// 处理数据 + /// + public ReceivedEventHandler Received { get; set; } + + /// + /// + /// + /// + /// + /// + protected override void OnReceived(SocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + Received?.Invoke(socketClient, byteBlock, requestInfo); + base.OnReceived(socketClient, byteBlock, requestInfo); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs.meta new file mode 100644 index 0000000..584a789 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59071a4eed57bd6409eb86c8990eaed8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs new file mode 100644 index 0000000..c0c79dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs @@ -0,0 +1,289 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// Tcp服务器基类 + /// + public abstract class TcpServiceBase : BaseSocket, ITcpService + { + /// + /// + /// + public abstract TouchSocketConfig Config { get; } + + /// + /// + /// + public abstract IContainer Container { get; } + + /// + /// + /// + public int Count => SocketClients.Count; + + /// + /// + /// + public abstract NetworkMonitor[] Monitors { get; } + + /// + /// 插件管理器 + /// + public abstract IPluginsManager PluginsManager { get; } + + /// + /// + /// + public abstract string ServerName { get; } + + /// + /// + /// + public abstract ServerState ServerState { get; } + + /// + /// + /// + public abstract SocketClientCollection SocketClients { get; } + + /// + /// + /// + public abstract bool UseSsl { get; } + + /// + /// + /// + public abstract Func GetDefaultNewID { get; } + + /// + /// + /// + public abstract int MaxCount { get; } + + /// + /// + /// + public abstract bool UsePlugin { get; } + + /// + /// + /// + public abstract void Clear(); + + /// + /// + /// + /// + public string[] GetIDs() + { + return SocketClients.GetIDs().ToArray(); + } + + /// + /// + /// + /// + /// + public abstract void ResetID(string oldID, string newID); + + /// + /// + /// + /// + /// + public abstract IService Setup(TouchSocketConfig serverConfig); + + /// + /// + /// + /// + /// + public abstract IService Setup(int port); + + /// + /// + /// + /// + public abstract IService Start(); + + /// + /// + /// + /// + public abstract IService Stop(); + + internal void OnInternalConnected(ISocketClient socketClient, TouchSocketEventArgs e) + { + OnClientConnected(socketClient, e); + } + + internal void OnInternalConnecting(ISocketClient socketClient, OperationEventArgs e) + { + OnClientConnecting(socketClient, e); + } + + internal void OnInternalDisconnected(ISocketClient socketClient, DisconnectEventArgs e) + { + OnClientDisconnected(socketClient, e); + } + + internal void OnInternalDisconnecting(ISocketClient socketClient, DisconnectEventArgs e) + { + OnClientDisconnecting(socketClient, e); + } + + internal void OnInternalReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + OnClientReceivedData(socketClient, byteBlock, requestInfo); + } + + /// + /// 客户端连接完成 + /// + /// + /// + protected abstract void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e); + + /// + /// 客户端请求连接 + /// + /// + /// + protected abstract void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e); + + /// + /// 客户端断开连接 + /// + /// + /// + protected abstract void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e); + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + protected abstract void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e); + + /// + /// 收到数据时 + /// + /// + /// + /// + protected abstract void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo); + + #region ID发送 + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public void Send(string id, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + client.Send(buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public void Send(string id, IRequestInfo requestInfo) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + client.Send(requestInfo); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(string id, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + return client.SendAsync(buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public Task SendAsync(string id, IRequestInfo requestInfo) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + return client.SendAsync(requestInfo); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public abstract bool SocketClientExist(string id); + + #endregion ID发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs.meta new file mode 100644 index 0000000..d8e4f13 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6262e2b104c924d41b7c6263252311a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP.meta new file mode 100644 index 0000000..ab21026 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2e696bd29cd2c24395e10e2391c5c3a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs new file mode 100644 index 0000000..4e7d600 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs @@ -0,0 +1,885 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 简单UDP会话。 + /// + public class UdpSession : UdpSessionBase + { + /// + /// 当收到数据时 + /// + public UdpReceivedEventHandler Received { get; set; } + + /// + /// + /// + /// + /// + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + Received?.Invoke(remoteEndPoint, byteBlock, requestInfo); + } + } + + /// + /// UDP基类服务器。 + /// + public class UdpSessionBase : BaseSocket, IUdpSession, IPluginObject + { + private readonly ConcurrentList m_socketAsyncs; + private TouchSocketConfig m_config; + private UdpDataHandlingAdapter m_adapter; + private NetworkMonitor m_monitor; + private IPHost m_remoteIPHost; + private ServerState m_serverState; + private bool m_usePlugin; + + /// + /// 构造函数 + /// + public UdpSessionBase() + { + m_socketAsyncs = new ConcurrentList(); + Protocol = Protocol.UDP; + Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + socket.ReceiveBufferSize = BufferLength; + socket.SendBufferSize = BufferLength; + m_monitor = new NetworkMonitor(null, socket); + } + + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public bool CanSend => m_serverState == ServerState.Running; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// 获取配置 + /// + public TouchSocketConfig Config => m_config; + + /// + /// + /// + public IContainer Container => m_config?.Container; + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// 数据处理适配器 + /// + public UdpDataHandlingAdapter DataHandlingAdapter => m_adapter; + + /// + /// 监听器 + /// + public NetworkMonitor Monitor => m_monitor; + + /// + /// + /// + public IPluginsManager PluginsManager => m_config?.PluginsManager; + + /// + /// + /// + public virtual Protocol Protocol { get; set; } + + /// + /// 默认远程节点 + /// + public IPHost RemoteIPHost => m_remoteIPHost; + + /// + /// 服务器名称 + /// + public string ServerName => Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty); + + /// + /// 获取服务器状态 + /// + public ServerState ServerState => m_serverState; + + /// + /// 是否已启用插件 + /// + public bool UsePlugin => m_usePlugin; + + /// + /// 退出组播 + /// + /// + public void DropMulticastGroup(IPAddress multicastAddr) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (multicastAddr is null) + { + throw new ArgumentNullException(nameof(multicastAddr)); + } + + if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork) + { + MulticastOption optionValue = new MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, optionValue); + } + else + { + IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.DropMembership, optionValue2); + } + } + + /// + /// 加入组播。 + /// 组播地址为 224.0.0.0 ~ 239.255.255.255,其中 224.0.0.0~224.255.255.255 不建议在用户程序中使用,因为它们一般都有特殊用途。 + /// + /// + public void JoinMulticastGroup(IPAddress multicastAddr) + { + if (multicastAddr is null) + { + throw new ArgumentNullException(nameof(multicastAddr)); + } + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork) + { + MulticastOption optionValue = new MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, optionValue); + } + else + { + IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, optionValue2); + } + } + + /// + /// 设置数据处理适配器 + /// + /// + public virtual void SetDataHandlingAdapter(UdpDataHandlingAdapter adapter) + { + if (!CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + SetAdapter(adapter); + } + + /// + /// + /// + /// + /// + public IService Setup(TouchSocketConfig config) + { + m_config = config; + if (config.IsUsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + LoadConfig(m_config); + if (UsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + return this; + } + + /// + /// 通过端口配置 + /// + /// + public IService Setup(int port) + { + TouchSocketConfig serverConfig = new TouchSocketConfig(); + serverConfig.SetBindIPHost(new IPHost(port)); + return Setup(serverConfig); + } + + /// + /// 启动服务 + /// + public IService Start() + { + try + { + if (m_serverState == ServerState.Disposed) + { + throw new Exception("无法重新利用已释放对象"); + } + + switch (m_serverState) + { + case ServerState.None: + { + if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost) + { + BeginReceive(iPHost); + } + + break; + } + case ServerState.Running: + return this; + + case ServerState.Stopped: + { + if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost) + { + BeginReceive(iPHost); + } + break; + } + case ServerState.Disposed: + { + throw new Exception("无法再次利用已释放对象"); + } + } + + m_serverState = ServerState.Running; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + catch (Exception ex) + { + m_serverState = ServerState.Exception; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.Message }) ; + } + throw; + } + + } + + /// + /// 停止服务器 + /// + public IService Stop() + { + m_monitor?.Socket.Dispose(); + m_monitor = null; + m_serverState = ServerState.Stopped; + foreach (var item in m_socketAsyncs) + { + item.SafeDispose(); + } + m_socketAsyncs.Clear(); + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!this.DisposedValue) + { + if (disposing) + { + m_monitor?.Socket.Dispose(); + m_monitor = null; + m_serverState = ServerState.Disposed; + foreach (var item in m_socketAsyncs) + { + item.SafeDispose(); + } + m_socketAsyncs.Clear(); + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + } + } + base.Dispose(disposing); + } + + /// + /// 处理已接收到的数据。 + /// + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(EndPoint endPoint, byte[] buffer, int offset, int length) + { + return true; + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + Logger = Container.Resolve(); + m_remoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + m_usePlugin = config.IsUsePlugin; + + if (CanSetDataHandlingAdapter) + { + SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.UdpDataHandlingAdapterProperty).Invoke()); + } + } + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(UdpDataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (adapter.m_owner != null) + { + throw new Exception("此适配器已被其他终端使用,请重新创建对象。"); + } + + if (Config != null) + { + if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + } + adapter.m_owner = this; + adapter.ReceivedCallBack = PrivateHandleReceivedData; + adapter.SendCallBack = DefaultSend; + m_adapter = adapter; + } + + private void BeginReceive(IPHost iPHost) + { + int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty); + threadCount = threadCount < 0 ? 1 : threadCount; + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Dgram, ProtocolType.Udp) + { + ReceiveBufferSize = BufferLength, + SendBufferSize = BufferLength, + EnableBroadcast = m_config.GetValue(TouchSocketConfigExtension.EnableBroadcastProperty) + }; + if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + PreviewBind(socket); + + #region Windows下UDP连接被重置错误10054 + +#if NET45_OR_GREATER + const int SIP_UDP_CONNRESET = -1744830452; + socket.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null); +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + const int SIP_UDP_CONNRESET = -1744830452; + socket.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null); + } +#endif + + #endregion + + socket.Bind(iPHost.EndPoint); + + m_monitor = new NetworkMonitor(iPHost, socket); + + switch (m_config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty)) + { + case ReceiveType.Auto: + { +#if NET45_OR_GREATER||NET5_0_OR_GREATER + for (int i = 0; i < threadCount; i++) + { + SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs(); + m_socketAsyncs.Add(eventArg); + eventArg.Completed += IO_Completed; + ByteBlock byteBlock = new ByteBlock(BufferLength); + eventArg.UserToken = byteBlock; + eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + eventArg.RemoteEndPoint = iPHost.EndPoint; + if (!socket.ReceiveFromAsync(eventArg)) + { + ProcessReceive(socket, eventArg); + } + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + for (int i = 0; i < threadCount; i++) + { + SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs(); + m_socketAsyncs.Add(eventArg); + eventArg.Completed += IO_Completed; + ByteBlock byteBlock = new ByteBlock(BufferLength); + eventArg.UserToken = byteBlock; + eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + eventArg.RemoteEndPoint = iPHost.EndPoint; + if (!socket.ReceiveFromAsync(eventArg)) + { + ProcessReceive(socket, eventArg); + } + } + } + else + { + Thread thread = new Thread(Received); + thread.IsBackground = true; + thread.Start(); + } +#endif + break; + } + default: + throw new Exception("UDP中只支持Auto模式"); + } + } + + private void Received() + { + while (true) + { + ByteBlock byteBlock = new ByteBlock(); + try + { + EndPoint endPoint = m_monitor.IPHost.EndPoint; + int r = m_monitor.Socket.ReceiveFrom(byteBlock.Buffer, ref endPoint); + byteBlock.SetLength(r); + HandleBuffer(endPoint, byteBlock); + } + catch (Exception ex) + { + byteBlock.Dispose(); + Logger.Log(LogType.Error, this, ex.Message, ex); + break; + } + } + } + + private void HandleBuffer(EndPoint endPoint, ByteBlock byteBlock) + { + try + { + LastReceivedTime = DateTime.Now; + if (OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + m_adapter.ReceivedInput(endPoint, byteBlock); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + private void IO_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessReceive((Socket)sender, e); + } + + private void PrivateHandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + + if (m_usePlugin) + { + UdpReceivedDataEventArgs args = new UdpReceivedDataEventArgs(remoteEndPoint, byteBlock, requestInfo); + PluginsManager.Raise(nameof(IUdpSessionPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + HandleReceivedData(remoteEndPoint, byteBlock, requestInfo); + } + + #region 向默认远程同步发送 + + /// + /// 向默认终结点发送 + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (m_remoteIPHost == null) + { + throw new Exception("默认终结点为空"); + } + Send(m_remoteIPHost.EndPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + public virtual void Send(IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!m_adapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + m_adapter.SendInput(requestInfo); + } + + #endregion 向默认远程同步发送 + + #region 向默认远程异步发送 + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + Send(requestInfo); + }); + } + + #endregion 向默认远程异步发送 + + #region 向设置的远程同步发送 + + /// + /// 向设置的远程同步发送 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(EndPoint remoteEP, byte[] buffer, int offset, int length) + { + m_adapter.SendInput(remoteEP, buffer, offset, length); + } + + #endregion 向设置的远程同步发送 + + #region 向设置的远程异步发送 + + /// + /// 向设置的远程异步发送 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(EndPoint remoteEP, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(remoteEP, buffer, offset, length); + }); + } + + #endregion 向设置的远程异步发送 + + private void ProcessReceive(Socket socket, SocketAsyncEventArgs e) + { + if (m_serverState == ServerState.Running && e.SocketError == SocketError.Success) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + + HandleBuffer(e.RemoteEndPoint, byteBlock); + + ByteBlock newByteBlock = new ByteBlock(BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + try + { + if (!socket.ReceiveFromAsync(e)) + { + ProcessReceive(socket, e); + } + } + catch (System.Exception ex) + { + Logger.Log(LogType.Error, this, ex.Message, ex); + } + } + else + { + if (e.SocketError != SocketError.Success) + { + Logger?.Error(this, $"接收出现错误:{e.SocketError},错误代码:{(int)e.SocketError}"); + e.Dispose(); + } + } + } + + #region DefaultSend + + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + DefaultSend(m_remoteIPHost.EndPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + if (HandleSendingData(endPoint, buffer, offset, length)) + { + if (CanSend) + { + m_monitor.Socket.SendTo(buffer, offset, length, SocketFlags.None, endPoint); + } + + LastSendTime = DateTime.Now; + } + } + + #endregion DefaultSend + + #region DefaultSendAsync + + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(EndPoint endPoint, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + #endregion DefaultSendAsync + + #region 组合发送 + + /// + /// + /// + /// + public void Send(IList> transferBytes) + { + Send(m_remoteIPHost.EndPoint, transferBytes); + } + + /// + /// + /// + /// + /// + public void Send(EndPoint endPoint, IList> transferBytes) + { + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + + if (!m_adapter.CanSplicingSend) + { + throw new NotSupportedException("该适配器不支持拼接发送"); + } + m_adapter.SendInput(endPoint, transferBytes); + } + + /// + /// + /// + /// + public Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(transferBytes); + }); + } + + /// + /// + /// + /// + /// + public Task SendAsync(EndPoint endPoint, IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(endPoint, transferBytes); + }); + } + + #endregion 组合发送 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs.meta new file mode 100644 index 0000000..7b99292 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Components/UDP/UdpSession.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42a5c9acda11a824d83093a81d2176d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config.meta new file mode 100644 index 0000000..21c3f1e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e9d9e386ad8dba4383395d62379b230 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs new file mode 100644 index 0000000..31fafa4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs @@ -0,0 +1,623 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Security.Authentication; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TouchSocketConfigBuilder配置扩展 + /// + public static class TouchSocketConfigExtension + { + #region 数据 + + /// + /// 接收缓存容量,默认1024*64,其作用有两个: + /// + /// 指示单次可接受的最大数据量 + /// 指示常规申请内存块的长度 + /// + /// 所需类型 + /// + public static readonly DependencyProperty BufferLengthProperty = + DependencyProperty.Register("BufferLength", typeof(TouchSocketConfigExtension), 1024 * 64); + + /// + /// 数据处理适配器,默认为获取 + /// 所需类型 + /// + public static readonly DependencyProperty> DataHandlingAdapterProperty = DependencyProperty>.Register("DataHandlingAdapter", typeof(TouchSocketConfigExtension), (Func)(() => { return new NormalDataHandlingAdapter(); })); + + /// + /// 接收类型,默认为 + /// 为自动接收数据,然后主动触发。 + /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开 + /// 所需类型 + /// + public static readonly DependencyProperty ReceiveTypeProperty = DependencyProperty.Register("ReceiveType", typeof(TouchSocketConfigExtension), ReceiveType.Auto); + + /// + /// 数据处理适配器,默认为获取 + /// 所需类型 + /// + public static readonly DependencyProperty> UdpDataHandlingAdapterProperty = DependencyProperty>.Register("UdpDataHandlingAdapter", typeof(TouchSocketConfigExtension), (Func)(() => { return new NormalUdpDataHandlingAdapter(); })); + + /// + /// 接收缓存容量,默认1024*64,其作用有两个: + /// + /// 指示单次可接受的最大数据量 + /// 指示常规申请内存块的长度 + /// + /// + /// + /// + /// + public static TouchSocketConfig SetBufferLength(this TouchSocketConfig config, int value) + { + config.SetValue(BufferLengthProperty, value); + return config; + } + + /// + /// 设置(Tcp系)数据处理适配器。 + /// + /// + /// + /// + public static TouchSocketConfig SetDataHandlingAdapter(this TouchSocketConfig config, Func value) + { + config.SetValue(DataHandlingAdapterProperty, value); + return config; + } + + /// + /// 接收类型,默认为 + /// 为自动接收数据,然后主动触发。 + /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开 + /// + /// + /// + /// + public static TouchSocketConfig SetReceiveType(this TouchSocketConfig config, ReceiveType value) + { + config.SetValue(ReceiveTypeProperty, value); + return config; + } + + /// + /// 设置(Udp系)数据处理适配器。 + /// + /// + /// + /// + public static TouchSocketConfig SetUdpDataHandlingAdapter(this TouchSocketConfig config, Func value) + { + config.SetValue(UdpDataHandlingAdapterProperty, value); + return config; + } + + #endregion 数据 + + #region ServiceBase + + /// + /// 服务名称,用于标识,无实际意义,所需类型 + /// + public static readonly DependencyProperty ServerNameProperty = DependencyProperty.Register("ServerName", typeof(TouchSocketConfigExtension), "TouchSocketServer"); + + /// + /// 多线程数量。默认-1缺省。 + /// TCP模式中,该值等效于 + /// UDP模式中,该值为重叠IO并发数 + /// 所需类型 + /// + public static readonly DependencyProperty ThreadCountProperty = DependencyProperty.Register("ThreadCount", typeof(TouchSocketConfigExtension), -1); + + /// + /// 服务名称,用于标识,无实际意义 + /// + /// + /// + /// + public static TouchSocketConfig SetServerName(this TouchSocketConfig config, string value) + { + config.SetValue(ServerNameProperty, value); + return config; + } + + /// + /// 多线程数量,默认为-1缺省,实际上在tcp中相当于值10,udp中相当于1。 + /// TCP模式中,该值等效于 + /// UDP模式中,该值为重叠IO并发数 + /// + /// + /// + /// + public static TouchSocketConfig SetThreadCount(this TouchSocketConfig config, int value) + { + config.SetValue(ThreadCountProperty, value); + return config; + } + + #endregion ServiceBase + + #region 适配器配置 + + /// + /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty CacheTimeoutEnableProperty = DependencyProperty.Register("CacheTimeoutEnable", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value) + { + config.SetValue(CacheTimeoutEnableProperty, value); + return config; + } + + /// + /// 适配器数据包缓存时长。默认为缺省()。当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty CacheTimeoutProperty = DependencyProperty.Register("CacheTimeout", typeof(TouchSocketConfigExtension), TimeSpan.Zero); + + /// + /// 适配器数据包缓存时长。默认为缺省()。当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value) + { + config.SetValue(CacheTimeoutProperty, value); + return config; + } + + /// + /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty UpdateCacheTimeWhenRevProperty = DependencyProperty.Register("UpdateCacheTimeWhenRev", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value) + { + config.SetValue(UpdateCacheTimeWhenRevProperty, value); + return config; + } + + /// + /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = DependencyProperty.Register("MaxPackageSize", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value) + { + config.SetValue(MaxPackageSizeProperty, value); + return config; + } + + #endregion 适配器配置 + + #region TcpClient + + /// + /// TCP固定端口绑定, + /// 所需类型 + /// + public static readonly DependencyProperty BindIPHostProperty = DependencyProperty.Register("BindIPHost", typeof(TouchSocketConfigExtension), null); + + /// + /// 在Socket配置KeepAlive属性,这个是操作tcp底层的,如果你对底层不了解,建议不要动。 + /// 所需类型 + /// + public static readonly DependencyProperty KeepAliveValueProperty = DependencyProperty.Register("KeepAliveValue", typeof(TouchSocketConfigExtension), new KeepAliveValue()); + + /// + /// 设置Socket不使用Delay算法, + /// 所需类型 + /// + public static readonly DependencyProperty NoDelayProperty = DependencyProperty.Register("NoDelay", typeof(TouchSocketConfigExtension), false); + + /// + /// 远程目标地址,所需类型 + /// + public static readonly DependencyProperty RemoteIPHostProperty = DependencyProperty.Register("RemoteIPHost", typeof(TouchSocketConfigExtension), null); + + /// + /// Ssl配置,为Null时则不启用 + /// 所需类型 + /// + public static readonly DependencyProperty SslOptionProperty = DependencyProperty.Register("SslOption", typeof(TouchSocketConfigExtension), null); + + /// + /// 是否使用延迟合并发送。默认null。不开启 + /// 所需类型 + /// + public static readonly DependencyProperty DelaySenderProperty = DependencyProperty.Register("DelaySender", typeof(TouchSocketConfigExtension), null); + + /// + /// 使用默认配置延迟合并发送。 + /// 所需类型 + /// + /// + /// + /// + public static TouchSocketConfig UseDelaySender(this TouchSocketConfig config, DelaySenderOption option = default) + { + if (option == default) + { + option = new DelaySenderOption(); + } + config.SetValue(DelaySenderProperty, option); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, IPHost value) + { + config.SetValue(BindIPHostProperty, value); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, int value) + { + config.SetValue(BindIPHostProperty, new IPHost(value)); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, string value) + { + config.SetValue(BindIPHostProperty, new IPHost(value)); + return config; + } + + /// + /// 设置客户端Ssl配置,为Null时则不启用。 + /// + /// + /// + /// + public static TouchSocketConfig SetClientSslOption(this TouchSocketConfig config, ClientSslOption value) + { + config.SetValue(SslOptionProperty, value); + return config; + } + + /// + /// 在Socket的KeepAlive属性。 + /// 注意:这个是操作tcp底层的,如果你对底层不了解,建议不要动。 + /// + /// + /// + /// + public static TouchSocketConfig SetKeepAliveValue(this TouchSocketConfig config, KeepAliveValue value) + { + config.SetValue(KeepAliveValueProperty, value); + return config; + } + + /// + /// 设置远程目标地址。在中,表示默认发送时的目标地址。 + /// + /// + /// + /// + public static TouchSocketConfig SetRemoteIPHost(this TouchSocketConfig config, IPHost value) + { + config.SetValue(RemoteIPHostProperty, value); + if (value.IsUri) + { + if (value.Uri.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase) + || value.Uri.Scheme.Equals("wss", StringComparison.CurrentCultureIgnoreCase) + || value.Uri.Scheme.Equals("ssl", StringComparison.CurrentCultureIgnoreCase) + || value.Uri.Scheme.Equals("tls", StringComparison.CurrentCultureIgnoreCase)) + { + config.SetClientSslOption(new ClientSslOption() + { + TargetHost = value.Host + }); + } + } + return config; + } + + /// + /// 设置远程目标地址。在中,表示默认发送时的目标地址。 + /// + /// + /// + /// + public static TouchSocketConfig SetRemoteIPHost(this TouchSocketConfig config, string value) + { + return SetRemoteIPHost(config, new IPHost(value)); + } + + /// + /// 设置Socket的NoDelay属性,默认false。 + /// + /// + /// + public static TouchSocketConfig UseNoDelay(this TouchSocketConfig config) + { + config.SetValue(NoDelayProperty, true); + return config; + } + + #endregion TcpClient + + #region TcpService + + /// + /// 挂起连接队列的最大长度,所需类型 + /// + public static readonly DependencyProperty BacklogProperty = DependencyProperty.Register("Backlog", typeof(TouchSocketConfigExtension), 100); + + /// + /// 设置默认ID的获取方式,所需类型 + /// + public static readonly DependencyProperty> GetDefaultNewIDProperty = DependencyProperty>.Register("GetDefaultNewID", typeof(TouchSocketConfigExtension), null); + + /// + /// 服务器负责监听的地址组。所需类型数组 + /// + public static readonly DependencyProperty ListenIPHostsProperty = DependencyProperty.Register("ListenIPHosts", typeof(TouchSocketConfigExtension), null); + + /// + /// 最大可连接数,默认为10000,所需类型 + /// + public static readonly DependencyProperty MaxCountProperty = DependencyProperty.Register("MaxCount", typeof(TouchSocketConfigExtension), 10000); + + /// + /// 端口复用,默认为false,所需类型 + /// + public static readonly DependencyProperty ReuseAddressProperty = DependencyProperty.Register("ReuseAddress", typeof(TouchSocketConfigExtension), false); + + /// + /// 启用端口复用。 + /// 该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题 + /// + /// + /// + public static TouchSocketConfig UseReuseAddress(this TouchSocketConfig config) + { + config.SetValue(ReuseAddressProperty, true); + return config; + } + + /// + /// 挂起连接队列的最大长度,默认100。 + /// + /// + /// + /// + public static TouchSocketConfig SetBacklog(this TouchSocketConfig config, int value) + { + config.SetValue(BacklogProperty, value); + return config; + } + + /// + /// 设置清理无数据交互的SocketClient,默认60*1000 ms。如果不想清除,可使用-1 + /// + /// + /// + /// + [Obsolete("该操作已被弃用,请使用CheckClearPlugin插件,或者在插件中,配置UseCheckClear。", true)] + public static TouchSocketConfig SetClearInterval(this TouchSocketConfig config, int value) + { + throw new NotImplementedException(); + } + + /// + /// 清理统计类型。 + /// 为在收到数据时,刷新统计,如果一直有数据接收,则不会被主动清理断开 + /// 为在发送数据时,刷新统计,如果一直有数据发送,则不会被主动清理断开 + /// 二者可叠加使用。 + /// + /// + /// + /// + [Obsolete("该操作已被弃用,请使用CheckClearPlugin插件,或者在插件中,配置UseCheckClear。", true)] + public static TouchSocketConfig SetClearType(this TouchSocketConfig config, CheckClearType value) + { + throw new NotImplementedException(); + } + + /// + /// 设置默认ID的获取方式。仅服务器生效。 + /// + /// + /// + /// + public static TouchSocketConfig SetGetDefaultNewID(this TouchSocketConfig config, Func value) + { + config.SetValue(GetDefaultNewIDProperty, value); + return config; + } + + /// + /// 服务器负责监听的地址组。 + /// + /// + /// + /// + public static TouchSocketConfig SetListenIPHosts(this TouchSocketConfig config, IPHost[] value) + { + config.SetValue(ListenIPHostsProperty, value); + return config; + } + + /// + /// 最大可连接数,默认为10000。 + /// + /// + /// + /// + public static TouchSocketConfig SetMaxCount(this TouchSocketConfig config, int value) + { + config.SetValue(MaxCountProperty, value); + return config; + } + + /// + /// 设置客户端Ssl配置,为Null时则不启用。 + /// + /// + /// + /// + public static TouchSocketConfig SetServiceSslOption(this TouchSocketConfig config, ServiceSslOption value) + { + config.SetValue(SslOptionProperty, value); + return config; + } + + #endregion TcpService + + #region UDP + + /// + /// 该值指定 System.Net.Sockets.Socket可以发送或接收广播数据包。 + /// + public static readonly DependencyProperty EnableBroadcastProperty = DependencyProperty.Register("EnableBroadcast", typeof(TouchSocketConfigExtension), false); + + /// + /// 该值指定 System.Net.Sockets.Socket可以发送或接收广播数据包。 + /// + /// + /// + public static TouchSocketConfig UseBroadcast(this TouchSocketConfig config) + { + config.SetValue(EnableBroadcastProperty, true); + return config; + } + + #endregion UDP + + #region 创建 + + /// + /// 构建Tcp类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithTcpClient(this TouchSocketConfig config) where TClient : ITcpClient + { + TClient service = config.Container.Resolve(); + service.Setup(config); + service.Connect(); + return service; + } + + /// + /// 构建Tcp类客户端,并连接 + /// + /// + /// + public static TcpClient BuildWithTcpClient(this TouchSocketConfig config) + { + return BuildWithTcpClient(config); + } + + /// + /// 构建Tcp类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithTcpService(this TouchSocketConfig config) where TService : ITcpService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建Tcp类服务器,并启动。 + /// + /// + /// + public static TcpService BuildWithTcpService(this TouchSocketConfig config) + { + return BuildWithTcpService(config); + } + + /// + /// 构建UDP类,并启动。 + /// + /// + /// + /// + public static TSession BuildWithUdpSession(this TouchSocketConfig config) where TSession : IUdpSession + { + TSession service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建UDP类,并启动。 + /// + /// + /// + public static UdpSession BuildWithUdpSession(this TouchSocketConfig config) + { + return BuildWithUdpSession(config); + } + + #endregion 创建 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs.meta new file mode 100644 index 0000000..eda9755 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bf2694d4d046914f8ca06e60cf129c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter.meta new file mode 100644 index 0000000..ec1169a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9749db990a144ec44ab9fe260924af6b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs new file mode 100644 index 0000000..a4f3097 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// CacheDataHandlingAdapter + /// + public abstract class CacheDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock m_cacheByteBlock; + + /// + /// 将数据缓存起来 + /// + /// + /// + /// + protected void Cache(byte[] buffer, int offset, int length) + { + this.m_cacheByteBlock ??= new ByteBlock(length); + this.m_cacheByteBlock.Write(buffer, offset, length); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + + /// + /// + /// + protected override void Reset() + { + this.m_cacheByteBlock.SafeDispose(); + this.m_cacheByteBlock = null; + base.Reset(); + } + + /// + /// 获取当前缓存, + /// 如果缓存超时,或者不存在,均会返回false。 + /// 如果获取成功,则会清空内部缓存。 + /// + /// + protected bool TryGetCache(out byte[] buffer) + { + if (this.m_cacheByteBlock == null) + { + buffer = null; + return false; + } + if (DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.m_cacheByteBlock.SafeDispose(); + this.m_cacheByteBlock = null; + buffer = null; + return false; + } + buffer = this.m_cacheByteBlock.ToArray(); + this.m_cacheByteBlock.SafeDispose(); + this.m_cacheByteBlock = null; + return true; + } + + /// + /// 获取缓存,注意:获取的ByteBlock需要手动释放。 + /// + /// + /// + protected bool TryGetCache(out ByteBlock byteBlock) + { + if (this.m_cacheByteBlock == null) + { + byteBlock = null; + return false; + } + if (DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.m_cacheByteBlock.SafeDispose(); + this.m_cacheByteBlock = null; + byteBlock = null; + return false; + } + byteBlock = this.m_cacheByteBlock; + return true; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..f4fccb8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: efa398ca70cf9524998acc24d2e0530c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom.meta new file mode 100644 index 0000000..8486059 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e847cea5dbc4183439cfdbc095adaada +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs new file mode 100644 index 0000000..35cd5a1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 区间数据包处理适配器,支持以任意字符、字节数组起始与结尾的数据包。 + /// + public abstract class CustomBetweenAndDataHandlingAdapter : CustomDataHandlingAdapter where TBetweenAndRequestInfo : class, IBetweenAndRequestInfo + { + /// + /// 起始字符,不可以为null,可以为0长度 + /// + public abstract byte[] StartCode { get; } + + /// + /// 即使找到了终止因子,也不会结束,默认0 + /// + public int MinSize { get; set; } + + /// + /// 结束字符,不可以为null,不可以为0长度,必须具有有效值。 + /// + public abstract byte[] EndCode { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TBetweenAndRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + int len; + int pos = byteBlock.Pos; + while (true) + { + int indexEnd = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, this.EndCode); + if (indexEnd == -1) + { + byteBlock.Pos = pos; + return FilterResult.Cache; + } + + len = indexEnd - this.EndCode.Length - pos + 1; + if (len >= this.MinSize) + { + break; + } + byteBlock.Pos += len + this.EndCode.Length; + } + + byteBlock.Pos = pos; + request.OnParsingBody(byteBlock.ToArray(pos, len)); + byteBlock.Pos += len; + + if (request.OnParsingEndCode(byteBlock.ToArray(byteBlock.Pos, this.EndCode.Length))) + { + byteBlock.Pos += this.EndCode.Length; + return FilterResult.Success; + } + else + { + byteBlock.Pos += this.EndCode.Length; + return FilterResult.GoOn; + } + } + else + { + TBetweenAndRequestInfo requestInfo = this.GetInstance(); + + int indexStart = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, this.StartCode); + if (indexStart == -1) + { + return FilterResult.Cache; + } + if (!requestInfo.OnParsingStartCode(byteBlock.ToArray(byteBlock.Pos, this.StartCode.Length))) + { + byteBlock.Pos += this.StartCode.Length; + return FilterResult.GoOn; + } + byteBlock.Pos += this.StartCode.Length; + request = requestInfo; + + int len; + int pos = byteBlock.Pos; + while (true) + { + int indexEnd = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, this.EndCode); + if (indexEnd == -1) + { + byteBlock.Pos = pos; + return FilterResult.Cache; + } + + len = indexEnd - this.EndCode.Length - pos + 1; + if (len >= this.MinSize) + { + break; + } + byteBlock.Pos += len + this.EndCode.Length; + } + + byteBlock.Pos = pos; + request.OnParsingBody(byteBlock.ToArray(pos, len)); + byteBlock.Pos += len; + + if (request.OnParsingEndCode(byteBlock.ToArray(byteBlock.Pos, this.EndCode.Length))) + { + byteBlock.Pos += this.EndCode.Length; + return FilterResult.Success; + } + else + { + byteBlock.Pos += this.EndCode.Length; + return FilterResult.GoOn; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TBetweenAndRequestInfo GetInstance(); + } + + /// + /// 区间类型的适配器数据模型接口。 + /// + public interface IBetweenAndRequestInfo : IRequestInfo + { + /// + /// 当解析到起始字符时。 + /// + /// + /// + bool OnParsingStartCode(byte[] startCode); + + /// + /// 当解析数据体。 + /// 在此方法中,您必须手动保存Body内容 + /// + /// + void OnParsingBody(byte[] body); + + /// + /// 当解析到起始字符时。 + /// + /// + /// + bool OnParsingEndCode(byte[] endCode); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..97a205f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62ed90c709d5430409aa22d2474247c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs new file mode 100644 index 0000000..14cd22c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,169 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 大数据用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TFixedHeaderRequestInfo。 + /// + public abstract class CustomBigFixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter + where TFixedHeaderRequestInfo : class, IBigFixedHeaderRequestInfo + { + /// + /// 固定包头的长度。 + /// + public abstract int HeaderLength { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TFixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + while (this.m_surLen > 0 && byteBlock.CanRead) + { + int r = (int)Math.Min(this.m_surLen, byteBlock.CanReadLength); + try + { + request.OnAppendBody(byteBlock.Buffer, byteBlock.Pos, r); + this.m_surLen -= r; + byteBlock.Pos += r; + if (this.m_surLen == 0) + { + if (request.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + } + catch (Exception ex) + { + this.OnError(ex.Message, false, true); + } + } + return FilterResult.GoOn; + } + else + { + if (this.HeaderLength > byteBlock.CanReadLen) + { + return FilterResult.Cache; + } + + TFixedHeaderRequestInfo requestInfo = this.GetInstance(); + byteBlock.Read(out byte[] header, this.HeaderLength); + if (requestInfo.OnParsingHeader(header)) + { + request = requestInfo; + if (requestInfo.BodyLength == 0) + { + if (requestInfo.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + this.m_surLen = request.BodyLength; + + while (this.m_surLen > 0 && byteBlock.CanRead) + { + int r = (int)Math.Min(this.m_surLen, byteBlock.CanReadLength); + try + { + request.OnAppendBody(byteBlock.Buffer, byteBlock.Pos, r); + this.m_surLen -= r; + byteBlock.Pos += r; + if (this.m_surLen == 0) + { + if (request.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + } + catch (Exception ex) + { + this.OnError(ex.Message, false, true); + } + } + return FilterResult.GoOn; + } + else + { + return FilterResult.GoOn; + } + } + } + + private long m_surLen; + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TFixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义固定包头请求 + /// + public interface IBigFixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + long BodyLength { get; } + + /// + /// 当收到数据,由框架封送固定协议头。 + /// 您需要在此函数中,解析自己的固定包头,并且对赋值后续数据的长度,然后返回True。 + /// 如果返回false,则意味着放弃本次解析 + /// + /// + /// + bool OnParsingHeader(byte[] header); + + /// + /// 当收到数据,由框架封送数据。 + /// 您需要将有效数据自行保存。该方法可能会多次调用。 + /// + /// + /// + /// + /// 是否成功有效 + void OnAppendBody(byte[] buffer, int offset, int length); + + /// + /// 当完成数据接收时调用。 + /// 当返回False时,将不会把该对象向Received传递。 + /// + /// 是否成功有效 + bool OnFinished(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..f6711c1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ef168a4260a84d47b6c8a6e42b366d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs new file mode 100644 index 0000000..1e33a56 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs @@ -0,0 +1,201 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义数据处理适配器,使用该适配器时,接收方收到的数据中,将为null, + /// 同时将实现为TRequest,发送数据直接发送。 + /// 此处设计思路借鉴SuperSocket。 + /// + public abstract class CustomDataHandlingAdapter : DataHandlingAdapter where TRequest : class, IRequestInfo + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock TempByteBlock; + + /// + /// 缓存对象。 + /// + protected TRequest TempRequest; + + private bool m_needReset; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 默认不支持拼接发送 + /// + public override bool CanSplicingSend => false; + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected abstract FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TRequest request, ref int tempCapacity); + + /// + /// 成功执行接收以后。 + /// + /// + protected virtual void OnReceivedSuccess(TRequest request) + { + } + + /// + /// 即将执行。 + /// + /// + /// 返回值标识是否继续执行 + protected virtual bool OnReceivingSuccess(TRequest request) + { + return true; + } + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (this.m_needReset || this.CacheTimeoutEnable && DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.Reset(); + this.m_needReset = false; + } + if (this.TempByteBlock == null) + { + this.Single(byteBlock, false); + } + else + { + this.TempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = this.TempByteBlock; + this.TempByteBlock = null; + this.Single(block, true); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + } + + /// + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + this.GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + protected override void Reset() + { + this.TempByteBlock.SafeDispose(); + this.TempByteBlock = null; + this.TempRequest = default; + this.m_needReset = true; + base.Reset(); + } + + private void Single(ByteBlock byteBlock, bool temp) + { + byteBlock.Pos = 0; + while (byteBlock.Pos < byteBlock.Len) + { + if (this.m_needReset) + { + return; + } + int tempCapacity = 1024 * 64; + FilterResult filterResult = this.Filter(byteBlock, this.TempRequest != null, ref this.TempRequest, ref tempCapacity); + switch (filterResult) + { + case FilterResult.Success: + if (this.OnReceivingSuccess(this.TempRequest)) + { + this.GoReceived(null, this.TempRequest); + this.OnReceivedSuccess(this.TempRequest); + } + this.TempRequest = default; + break; + + case FilterResult.Cache: + if (byteBlock.CanReadLen > 0) + { + if (temp) + { + this.TempByteBlock = new ByteBlock(tempCapacity); + this.TempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + byteBlock.Dispose(); + } + else + { + this.TempByteBlock = new ByteBlock(tempCapacity); + this.TempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + } + + if (this.TempByteBlock.Len > this.MaxPackageSize) + { + this.OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + return; + + case FilterResult.GoOn: + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..8bf8c6d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba41558def354bf4aa5e21e1305819e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs new file mode 100644 index 0000000..a9d8854 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TFixedHeaderRequestInfo。 + /// + public abstract class CustomFixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter where TFixedHeaderRequestInfo : class, IFixedHeaderRequestInfo + { + /// + /// 固定包头的长度。 + /// + public abstract int HeaderLength { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TFixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + if (request.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, request.BodyLength); + if (request.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + if (this.HeaderLength > byteBlock.CanReadLen) + { + return FilterResult.Cache; + } + + TFixedHeaderRequestInfo requestInfo = this.GetInstance(); + byteBlock.Read(out byte[] header, this.HeaderLength); + if (requestInfo.OnParsingHeader(header)) + { + request = requestInfo; + if (requestInfo.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, requestInfo.BodyLength); + if (requestInfo.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + return FilterResult.GoOn; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TFixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义固定包头请求 + /// + public interface IFixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + int BodyLength { get; } + + /// + /// 当收到数据,由框架封送固定协议头。 + /// 您需要在此函数中,解析自己的固定包头,并且对赋值后续数据的长度,然后返回True。 + /// 如果返回false,则意味着放弃本次解析 + /// + /// + /// + bool OnParsingHeader(byte[] header); + + /// + /// 当收到数据,由框架封送有效载荷数据。 + /// 如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header + /// + /// 载荷数据 + /// 是否成功有效 + bool OnParsingBody(byte[] body); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..d153585 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d835486ae96cc2041b954b9989e13ddf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs new file mode 100644 index 0000000..cae96a8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TUnfixedHeaderRequestInfo。 + /// + public abstract class CustomUnfixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter where TUnfixedHeaderRequestInfo : class, IUnfixedHeaderRequestInfo + { + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TUnfixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + if (request.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, request.BodyLength); + if (request.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + TUnfixedHeaderRequestInfo requestInfo = this.GetInstance(); + if (requestInfo.OnParsingHeader(byteBlock)) + { + request = requestInfo; + if (requestInfo.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, requestInfo.BodyLength); + if (requestInfo.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + return FilterResult.Cache; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TUnfixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义不固定包头请求 + /// + public interface IUnfixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + int BodyLength { get; } + + /// + /// 当收到数据,由框架封送数据,您需要在此函数中,解析自己的数据包头。 + /// 如果满足包头的解析,请返回True,并且递增整个包头的长度到,然后赋值 + /// 如果返回false,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。 + /// 但是如果是因为数据错误,则需要修改到正确位置,如果都不正确,则设置等于 + /// + /// + /// 是否满足解析包头 + bool OnParsingHeader(ByteBlock byteBlock); + + /// + /// 当收到数据,由框架封送有效载荷数据。 + /// 如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header + /// + /// 载荷数据 + /// 是否成功有效 + bool OnParsingBody(byte[] body); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..3c6e601 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5754caace9bbdd04893aff9a718ca613 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs new file mode 100644 index 0000000..96629cf --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs @@ -0,0 +1,221 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 数据处理适配器 + /// + public abstract class DataHandlingAdapter : DisposableObject + { + + /// + /// 最后缓存的时间 + /// + protected DateTime LastCacheTime { get; set; } + + /// + /// 是否在收到数据时,即刷新缓存时间。默认true。 + /// + /// 当设为true时,将弱化的作用,只要一直有数据,则缓存不会过期。 + /// 当设为false时,则在的时效内。必须完成单个缓存的数据。 + /// + /// + public bool UpdateCacheTimeWhenRev { get; set; } = true; + + /// + /// 缓存超时时间。默认1秒。 + /// + public TimeSpan CacheTimeout { get; set; } = TimeSpan.FromSeconds(1); + + /// + /// 是否启用缓存超时。默认true。 + /// + public bool CacheTimeoutEnable { get; set; } = true; + + /// + /// 当插件在被第一次加载时调用。 + /// + /// + /// 此适配器已被其他终端使用,请重新创建对象。 + public virtual void OnLoaded(ITcpClientBase client) + { + if (this.Client != null) + { + throw new Exception("此适配器已被其他终端使用,请重新创建对象。"); + } + this.Client = client; + } + + /// + /// 拼接发送 + /// + public abstract bool CanSplicingSend { get; } + + /// + /// 是否允许发送对象。 + /// + public abstract bool CanSendRequestInfo { get; } + + /// + /// 获取或设置适配器能接收的最大数据包长度。 + /// + public int MaxPackageSize { get; set; } = 1024 * 1024 * 10; + + /// + /// 适配器拥有者。 + /// + public ITcpClientBase Client { get; private set; } + + /// + /// 当接收数据处理完成后,回调该函数执行接收 + /// + public Action ReceivedCallBack { get; set; } + + /// + /// 当接收数据处理完成后,回调该函数执行发送 + /// + public Action SendCallBack { get; set; } + + /// + /// 收到数据的切入点,该方法由框架自动调用。 + /// + /// + public void ReceivedInput(ByteBlock byteBlock) + { + try + { + this.PreviewReceived(byteBlock); + } + catch (Exception ex) + { + this.OnError(ex.Message); + } + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + /// + public void SendInput(byte[] buffer, int offset, int length) + { + this.PreviewSend(buffer, offset, length); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IList> transferBytes) + { + this.PreviewSend(transferBytes); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IRequestInfo requestInfo) + { + this.PreviewSend(requestInfo); + } + + /// + /// 处理已经经过预先处理后的数据 + /// + /// 以二进制形式传递 + /// 以解析实例传递 + protected void GoReceived(ByteBlock byteBlock, IRequestInfo requestInfo) + { + this.ReceivedCallBack.Invoke(byteBlock, requestInfo); + } + + /// + /// 发送已经经过预先处理后的数据 + /// + /// + /// + /// + protected void GoSend(byte[] buffer, int offset, int length) + { + this.SendCallBack.Invoke(buffer, offset, length); + } + + /// + /// 在解析时发生错误。 + /// + /// 错误异常 + /// 是否调用 + /// 是否记录日志 + protected virtual void OnError(string error, bool reset = true, bool log = true) + { + if (reset) + { + this.Reset(); + } + if (log && this.Client != null && this.Client.Logger != null) + { + this.Client.Logger.Error(error); + } + } + + /// + /// 当接收到数据后预先处理数据,然后调用处理数据 + /// + /// + protected abstract void PreviewReceived(ByteBlock byteBlock); + + /// + /// 当发送数据前预先处理数据 + /// + /// 数据 + /// 偏移 + /// 长度 + protected abstract void PreviewSend(byte[] buffer, int offset, int length); + + /// + /// 当发送数据前预先处理数据 + /// + /// + protected abstract void PreviewSend(IRequestInfo requestInfo); + + /// + /// 组合发送预处理数据, + /// 当属性SplicingSend实现为True时,系统才会调用该方法。 + /// + /// 代发送数据组合 + protected abstract void PreviewSend(IList> transferBytes); + + /// + /// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。 + /// + protected virtual void Reset() + { + this.LastCacheTime = DateTime.Now; + } + + /// + /// 该方法被触发时,一般说明已经断开连接。 + /// + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs.meta new file mode 100644 index 0000000..c9ce22e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f512df60c2f9014780697dee3f3b254 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs new file mode 100644 index 0000000..7c64601 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +//using TouchSocket.Core; +//using System.Collections.Generic; +//using System.Text; +//using System.Text.RegularExpressions; + +//namespace TouchSocket.Sockets +//{ +// /// +// /// Json字符串数据处理解析器(该解析器由网友"明月"提供) +// /// +// public class JsonStringDataHandlingAdapter : CustomDataHandlingAdapter +// { +// private ByteBlock Temp; + +// /// +// /// +// /// +// public override bool CanSplicingSend => false; + +// /// +// /// 预解析 +// /// +// /// +// protected override void PreviewReceived(ByteBlock byteBlock) +// { +// byte[] buffer = byteBlock.Buffer; +// int length = byteBlock.Len; + +// //Console.WriteLine("----------------接收的新数据-------------------"); +// if (Temp != null) +// { +// Temp.Write(byteBlock.Buffer, 0, length); +// buffer = Temp.Buffer; +// length = (int)Temp.Length; +// } + +// string msg = Encoding.UTF8.GetString(buffer, 0, length); +// if (msg.Contains("}{")) +// { +// //Console.WriteLine("----------------发生粘包-------------------"); +// string[] mes = Regex.Split(msg, "}{"); +// for (int i = 0; i < mes.Length; i++) +// { +// string str = mes[i]; +// if (i == 0) +// { +// str += "}"; +// } +// else if (i == mes.Length - 1) +// { +// str = "{" + str; +// int start = StringCount(str, "{"); +// int end = StringCount(str, "}"); +// if (start == end) +// { +// if (Temp != null) +// { +// Temp = null; +// } +// } +// else +// { +// byte[] surPlus = Encoding.UTF8.GetBytes(str); + +// if (Temp != null) +// { +// Temp = null; +// } +// //Temp = BytePool.GetByteBlock(1024*1024*10); +// Temp = BytePool.GetByteBlock(length); + +// Temp.Write(surPlus); +// //Console.WriteLine("----------------数据不完整-------------------"); +// break; +// } +// } +// else +// { +// str = "{" + str + "}"; +// } +// //Console.WriteLine(str); +// PreviewHandle(str); +// } +// } +// else if (msg[0] == '{' && msg[1] == '}') +// { +// Temp = null; +// PreviewHandle(msg); +// } +// else +// { +// if (Temp == null) +// { +// Temp = BytePool.GetByteBlock(length); +// Temp.Write(byteBlock.Buffer, 0, length); +// } + +// Temp.Write(byteBlock.Buffer, 0, length); +// } +// } + +// /// +// /// 预发送封装 +// /// +// /// +// /// +// /// +// /// +// protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) +// { +// this.GoSend(buffer, offset, length, isAsync); +// } + +// private int StringCount(string source, string match) +// { +// int count = 0; +// if (source.Contains(match)) +// { +// string temp = source.Replace(match, ""); +// count = (source.Length - temp.Length) / match.Length; +// } +// return count; +// } + +// private void PreviewHandle(string msg) +// { +// GoReceived(null, msg); +// } + +// protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref JsonRequestInfo request, ref int tempCapacity) +// { +// } +// } + +// /// +// /// json解析 +// /// +// public class JsonRequestInfo:IRequestInfo +// { +// } +//} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..7421ef4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6dcf38b8fa6149d49903620b8fc3da61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs new file mode 100644 index 0000000..c92fa18 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 普通TCP数据处理器,该适配器不对数据做任何处理。 + /// + public class NormalDataHandlingAdapter : DataHandlingAdapter + { + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + this.GoReceived(byteBlock, null); + } + + /// + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + this.GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + base.Reset(); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..8367220 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 086ce620918ab2b42916d76bced17faa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package.meta new file mode 100644 index 0000000..78d35fd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3333fe57e2e06942a1670c931a8ed38 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs new file mode 100644 index 0000000..d5334df --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs @@ -0,0 +1,348 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 固定包头数据包处理适配器,支持Byte、UShort、Int三种类型作为包头。使用大小端设置。 + /// + public class FixedHeaderPackageAdapter : DataHandlingAdapter + { + private byte[] m_agreementTempBytes; + private int m_surPlusLength = 0; + + //包剩余长度 + private ByteBlock m_tempByteBlock; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 设置包头类型,默认为int + /// + public FixedHeaderType FixedHeaderType { get; set; } = FixedHeaderType.Int; + + /// + /// 获取或设置包数据的最小值(默认为0) + /// + public int MinPackageSize { get; set; } = 0; + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + + if (this.CacheTimeoutEnable && DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.Reset(); + } + + if (this.m_agreementTempBytes != null) + { + this.SeamPackage(buffer, r); + } + else if (this.m_tempByteBlock == null) + { + this.SplitPackage(buffer, 0, r); + } + else + { + if (this.m_surPlusLength == r) + { + this.m_tempByteBlock.Write(buffer, 0, this.m_surPlusLength); + this.PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + this.m_surPlusLength = 0; + } + else if (this.m_surPlusLength < r) + { + this.m_tempByteBlock.Write(buffer, 0, this.m_surPlusLength); + this.PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + this.SplitPackage(buffer, this.m_surPlusLength, r); + } + else + { + this.m_tempByteBlock.Write(buffer, 0, r); + this.m_surPlusLength -= r; + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 当发送数据前处理数据 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + if (length < this.MinPackageSize) + { + throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + if (length > this.MaxPackageSize) + { + throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + ByteBlock byteBlock = null; + byte[] lenBytes = null; + + switch (this.FixedHeaderType) + { + case FixedHeaderType.Byte: + { + byte dataLen = (byte)(length - offset); + byteBlock = new ByteBlock(dataLen + 1); + lenBytes = new byte[] { dataLen }; + break; + } + case FixedHeaderType.Ushort: + { + ushort dataLen = (ushort)(length - offset); + byteBlock = new ByteBlock(dataLen + 2); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + case FixedHeaderType.Int: + { + int dataLen = length - offset; + byteBlock = new ByteBlock(dataLen + 4); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + } + + try + { + byteBlock.Write(lenBytes); + byteBlock.Write(buffer, offset, length); + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + if (transferBytes.Count == 0) + { + return; + } + + int length = 0; + foreach (ArraySegment item in transferBytes) + { + length += item.Count; + } + + if (length < this.MinPackageSize) + { + throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + if (length > this.MaxPackageSize) + { + throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + ByteBlock byteBlock = null; + byte[] lenBytes = null; + + switch (this.FixedHeaderType) + { + case FixedHeaderType.Byte: + { + byte dataLen = (byte)length; + byteBlock = new ByteBlock(dataLen + 1); + lenBytes = new byte[] { dataLen }; + break; + } + case FixedHeaderType.Ushort: + { + ushort dataLen = (ushort)length; + byteBlock = new ByteBlock(dataLen + 2); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + case FixedHeaderType.Int: + { + byteBlock = new ByteBlock(length + 4); + lenBytes = TouchSocketBitConverter.Default.GetBytes(length); + break; + } + } + + try + { + byteBlock.Write(lenBytes); + foreach (ArraySegment item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + this.m_agreementTempBytes = null; + this.m_surPlusLength = default; + this.m_tempByteBlock?.Dispose(); + this.m_tempByteBlock = null; + base.Reset(); + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 缝合包 + /// + /// + /// + private void SeamPackage(byte[] buffer, int r) + { + var byteBlock = new ByteBlock(r + this.m_agreementTempBytes.Length); + byteBlock.Write(this.m_agreementTempBytes); + byteBlock.Write(buffer, 0, r); + r += this.m_agreementTempBytes.Length; + this.m_agreementTempBytes = null; + this.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) + { + this.m_agreementTempBytes = new byte[r - index]; + Array.Copy(dataBuffer, index, this.m_agreementTempBytes, 0, this.m_agreementTempBytes.Length); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + return; + } + int length = 0; + + switch (this.FixedHeaderType) + { + case FixedHeaderType.Byte: + length = dataBuffer[index]; + break; + + case FixedHeaderType.Ushort: + length = TouchSocketBitConverter.Default.ToUInt16(dataBuffer, index); + break; + + case FixedHeaderType.Int: + length = TouchSocketBitConverter.Default.ToInt32(dataBuffer, index); + break; + } + + if (length < 0) + { + throw new Exception("接收数据长度错误,已放弃接收"); + } + else if (length < this.MinPackageSize) + { + throw new Exception("接收数据长度小于设定值,已放弃接收"); + } + else if (length > this.MaxPackageSize) + { + throw new Exception("接收数据长度大于设定值,已放弃接收"); + } + + int recedSurPlusLength = r - index - (byte)this.FixedHeaderType; + if (recedSurPlusLength >= length) + { + var byteBlock = new ByteBlock(length); + byteBlock.Write(dataBuffer, index + (byte)this.FixedHeaderType, length); + this.PreviewHandle(byteBlock); + this.m_surPlusLength = 0; + } + else//半包 + { + this.m_tempByteBlock = new ByteBlock(length); + this.m_surPlusLength = length - recedSurPlusLength; + this.m_tempByteBlock.Write(dataBuffer, index + (byte)this.FixedHeaderType, recedSurPlusLength); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + index += (length + (byte)this.FixedHeaderType); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs.meta new file mode 100644 index 0000000..5e5a45b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ec50c802778f0c40ad4fe26e8f891ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs new file mode 100644 index 0000000..7c9421c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs @@ -0,0 +1,225 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 固定长度数据包处理适配器。 + /// + public class FixedSizePackageAdapter : DataHandlingAdapter + { + /// + /// 包剩余长度 + /// + private int m_surPlusLength = 0; + + /// + /// 临时包 + /// + private ByteBlock m_tempByteBlock; + + /// + /// 构造函数 + /// + /// 数据包的长度 + public FixedSizePackageAdapter(int fixedSize) + { + this.FixedSize = fixedSize; + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 获取已设置的数据包的长度 + /// + public int FixedSize { get; private set; } + + /// + /// 预处理 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (this.CacheTimeoutEnable && DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.Reset(); + } + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (this.m_tempByteBlock == null) + { + this.SplitPackage(buffer, 0, r); + } + else + { + if (this.m_surPlusLength == r) + { + this.m_tempByteBlock.Write(buffer, 0, this.m_surPlusLength); + this.PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + this.m_surPlusLength = 0; + } + else if (this.m_surPlusLength < r) + { + this.m_tempByteBlock.Write(buffer, 0, this.m_surPlusLength); + this.PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + this.SplitPackage(buffer, this.m_surPlusLength, r); + } + else + { + this.m_tempByteBlock.Write(buffer, 0, r); + this.m_surPlusLength -= r; + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 预处理 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + int dataLen = length - offset; + if (dataLen > this.FixedSize) + { + throw new OverlengthException("发送的数据包长度大于FixedSize"); + } + var byteBlock = new ByteBlock(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 + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + int length = 0; + foreach (ArraySegment item in transferBytes) + { + length += item.Count; + } + + if (length > this.FixedSize) + { + throw new OverlengthException("发送的数据包长度大于FixedSize"); + } + var byteBlock = new ByteBlock(this.FixedSize); + + foreach (ArraySegment item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + + Array.Clear(byteBlock.Buffer, byteBlock.Pos, this.FixedSize); + byteBlock.SetLength(this.FixedSize); + try + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + this.m_tempByteBlock.SafeDispose(); + this.m_tempByteBlock = null; + this.m_surPlusLength = 0; + base.Reset(); + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + if (r - index >= this.FixedSize) + { + var byteBlock = new ByteBlock(this.FixedSize); + byteBlock.Write(dataBuffer, index, this.FixedSize); + this.PreviewHandle(byteBlock); + this.m_surPlusLength = 0; + } + else//半包 + { + this.m_tempByteBlock = new ByteBlock(this.FixedSize); + this.m_surPlusLength = this.FixedSize - (r - index); + this.m_tempByteBlock.Write(dataBuffer, index, r - index); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + index += this.FixedSize; + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs.meta new file mode 100644 index 0000000..9609397 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5fdd2c19976c219409c7766ac8297e29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs new file mode 100644 index 0000000..032fb54 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 终止字符数据包处理适配器,支持以任意字符、字节数组结尾的数据包。 + /// + public class TerminatorPackageAdapter : DataHandlingAdapter + { + private ByteBlock m_tempByteBlock; + + private readonly byte[] m_terminatorCode; + + /// + /// 构造函数 + /// + /// + public TerminatorPackageAdapter(string terminator) : this(0, Encoding.UTF8.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + public TerminatorPackageAdapter(string terminator, Encoding encoding) + : this(0, encoding.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + public TerminatorPackageAdapter(int minSize, byte[] terminatorCode) + { + this.MinSize = minSize; + this.m_terminatorCode = terminatorCode; + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 即使找到了终止因子,也不会结束,默认0 + /// + public int MinSize { get; set; } = 0; + + /// + /// 保留终止因子 + /// + public bool ReserveTerminatorCode { get; set; } + + /// + /// 预处理 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (this.CacheTimeoutEnable && DateTime.Now - this.LastCacheTime > this.CacheTimeout) + { + this.Reset(); + } + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (this.m_tempByteBlock != null) + { + this.m_tempByteBlock.Write(buffer, 0, r); + buffer = this.m_tempByteBlock.Buffer; + r = (int)this.m_tempByteBlock.Position; + } + + List indexes = buffer.IndexOfInclude(0, r, this.m_terminatorCode); + if (indexes.Count == 0) + { + if (r > this.MaxPackageSize) + { + this.Reset(); + this.Client?.Logger.Error("在已接收数据大于设定值的情况下未找到终止因子,已放弃接收"); + } + else if (this.m_tempByteBlock == null) + { + this.m_tempByteBlock = new ByteBlock(r * 2); + this.m_tempByteBlock.Write(buffer, 0, r); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + } + else + { + int startIndex = 0; + foreach (int lastIndex in indexes) + { + int length; + if (this.ReserveTerminatorCode) + { + length = lastIndex - startIndex + 1; + } + else + { + length = lastIndex - startIndex - this.m_terminatorCode.Length + 1; + } + + var packageByteBlock = new ByteBlock(length); + packageByteBlock.Write(buffer, startIndex, length); + + string mes = Encoding.UTF8.GetString(packageByteBlock.Buffer, 0, (int)packageByteBlock.Position); + + this.PreviewHandle(packageByteBlock); + startIndex = lastIndex + 1; + } + this.Reset(); + if (startIndex < r) + { + this.m_tempByteBlock = new ByteBlock((r - startIndex) * 2); + this.m_tempByteBlock.Write(buffer, startIndex, r - startIndex); + if (this.UpdateCacheTimeWhenRev) + { + this.LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 预处理 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + if (length > this.MaxPackageSize) + { + throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。"); + } + int dataLen = length - offset + this.m_terminatorCode.Length; + var byteBlock = new ByteBlock(dataLen); + byteBlock.Write(buffer, offset, length); + byteBlock.Write(this.m_terminatorCode); + + try + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + int length = 0; + foreach (ArraySegment item in transferBytes) + { + length += item.Count; + } + if (length > this.MaxPackageSize) + { + throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。"); + } + int dataLen = length + this.m_terminatorCode.Length; + var byteBlock = new ByteBlock(dataLen); + foreach (ArraySegment item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + + byteBlock.Write(this.m_terminatorCode); + + try + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + this.m_tempByteBlock.SafeDispose(); + this.m_tempByteBlock = null; + base.Reset(); + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs.meta new file mode 100644 index 0000000..f2dc23c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 888257d06ef47aa43bb3fbda1fb20a33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs new file mode 100644 index 0000000..c21f20e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Pipeline读取管道 + /// + public abstract class Pipeline : BlockReadStream, IRequestInfo + { + /// + /// Pipeline读取管道 + /// + /// + protected Pipeline(ITcpClientBase client) + { + this.Client = client; + } + + /// + /// 当前支持此管道的客户端。 + /// + public ITcpClientBase Client { get; set; } + } + + /// + /// 管道数据处理适配器。 + /// 使用该适配器后,将为. + /// + public class PipelineDataHandlingAdapter : NormalDataHandlingAdapter + { + private byte[] m_buffer; + private InternalPipeline m_pipeline; + + private Task m_task; + + /// + /// 管道数据处理适配器。 + /// 使用该适配器后,将为. + /// + public PipelineDataHandlingAdapter() + { + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + this.m_pipeline.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (this.m_pipeline == null || !this.m_pipeline.Enable) + { + this.m_task?.Wait(); + this.m_pipeline = new InternalPipeline(this.Client); + this.m_task = EasyTask.Run(() => + { + try + { + this.GoReceived(default, this.m_pipeline); + if (this.m_pipeline.CanReadLen > 0) + { + this.m_buffer = new byte[this.m_pipeline.CanReadLen]; + this.m_pipeline.Read(this.m_buffer, 0, this.m_buffer.Length); + } + } + catch + { + } + finally + { + this.m_pipeline.SafeDispose(); + } + }); + } + if (this.m_buffer != null) + { + this.m_pipeline.InternalInput(this.m_buffer, 0, this.m_buffer.Length); + this.m_buffer = null; + } + this.m_pipeline.InternalInput(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + internal class InternalPipeline : Pipeline + { + private readonly object m_locker = new object(); + + private bool m_disposedValue; + + /// + /// Pipeline读取管道 + /// + /// + public InternalPipeline(ITcpClientBase client) : base(client) + { + this.ReadTimeout = 60 * 1000; + } + + public override bool CanRead => this.Enable; + + public override bool CanWrite => this.Client.CanSend; + + public bool Enable + { + get + { + lock (this.m_locker) + { + return !this.m_disposedValue; + } + } + } + + public override void Flush() + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + this.Client.DefaultSend(buffer, offset, count); + } + + internal void InternalInput(byte[] buffer, int offset, int length) + { + this.Input(buffer, offset, length); + } + + protected override void Dispose(bool disposing) + { + lock (this.m_locker) + { + this.m_disposedValue = true; + base.Dispose(disposing); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..83dddcc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4d5d95e3bb2b144cb58640c36f42823 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test.meta new file mode 100644 index 0000000..ca9992b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 790dbfbc20d5c6546915c17c244a8dcd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs new file mode 100644 index 0000000..6097c66 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs @@ -0,0 +1,368 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 数据处理适配器测试 + /// + public class DataAdapterTester : IDisposable + { + private readonly IntelligentDataQueue asyncBytes; + private readonly Thread sendThread; + private DataHandlingAdapter adapter; + private int bufferLength; + private int count; + private bool dispose; + private int expectedCount; + private Action receivedCallBack; + private Stopwatch stopwatch; + private int timeout; + + private DataAdapterTester() + { + this.asyncBytes = new IntelligentDataQueue(1024 * 1024 * 10); + this.sendThread = new Thread(this.BeginSend); + this.sendThread.IsBackground = true; + this.sendThread.Name = "DataAdapterTesterThread"; + this.sendThread.Start(); + } + + /// + /// 获取测试器 + /// + /// 待测试适配器 + /// 收到数据回调 + /// 缓存数据长度 + /// + public static DataAdapterTester CreateTester(DataHandlingAdapter adapter, int bufferLength = 1024, Action receivedCallBack = default) + { + var tester = new DataAdapterTester(); + tester.adapter = adapter; + tester.bufferLength = bufferLength; + adapter.SendCallBack = tester.SendCallback; + adapter.ReceivedCallBack = tester.OnReceived; + tester.receivedCallBack = receivedCallBack; + return tester; + } + + /// + /// 释放 + /// + public void Dispose() + { + this.dispose = true; + } + + /// + /// 模拟测试运行发送 + /// + /// + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + /// + public TimeSpan Run(byte[] buffer, int offset, int length, int testCount, int expectedCount, int timeout) + { + this.count = 0; + this.expectedCount = expectedCount; + this.timeout = timeout; + this.stopwatch = new Stopwatch(); + this.stopwatch.Start(); + EasyTask.Run(() => + { + for (int i = 0; i < testCount; i++) + { + this.adapter.SendInput(buffer, offset, length); + } + }); + + if (SpinWait.SpinUntil(() => this.count == this.expectedCount, this.timeout)) + { + this.stopwatch.Stop(); + return this.stopwatch.Elapsed; + } + throw new TimeoutException(); + } + + /// + /// 模拟发送 + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + public TimeSpan Run(byte[] buffer, int testCount, int expectedCount, int timeout) + { + return this.Run(buffer, 0, buffer.Length, testCount, expectedCount, timeout); + } + + private void BeginSend() + { + while (!this.dispose) + { + if (this.tryGet(out List byteBlocks)) + { + foreach (ByteBlock block in byteBlocks) + { + try + { + this.adapter.ReceivedInput(block); + } + finally + { + block.Dispose(); + } + } + } + else + { + Thread.Sleep(1); + } + } + } + + private void OnReceived(ByteBlock byteBlock, IRequestInfo requestInfo) + { + this.count++; + this.receivedCallBack?.Invoke(byteBlock, requestInfo); + } + + private void SendCallback(byte[] buffer, int offset, int length) + { + var asyncByte = new QueueDataBytes(new byte[length], 0, length); + Array.Copy(buffer, offset, asyncByte.Buffer, 0, length); + this.asyncBytes.Enqueue(asyncByte); + } + + private bool tryGet(out List byteBlocks) + { + byteBlocks = new List(); + ByteBlock block = null; + while (true) + { + if (this.asyncBytes.TryDequeue(out QueueDataBytes asyncByte)) + { + if (block == null) + { + block = BytePool.Default.GetByteBlock(this.bufferLength); + byteBlocks.Add(block); + } + int surLen = this.bufferLength - block.Pos; + if (surLen < asyncByte.Length)//不能完成写入 + { + block.Write(asyncByte.Buffer, asyncByte.Offset, surLen); + int offset = surLen; + while (offset < asyncByte.Length) + { + block = this.Write(asyncByte, ref offset); + byteBlocks.Add(block); + } + + if (byteBlocks.Count > 10) + { + break; + } + } + else//本次能完成写入 + { + block.Write(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + if (byteBlocks.Count > 10) + { + break; + } + } + } + else + { + if (byteBlocks.Count > 0) + { + break; + } + else + { + return false; + } + } + } + return true; + } + + private ByteBlock Write(QueueDataBytes transferByte, ref int offset) + { + ByteBlock block = BytePool.Default.GetByteBlock(this.bufferLength, true); + int len = Math.Min(transferByte.Length - offset, this.bufferLength); + block.Write(transferByte.Buffer, offset, len); + offset += len; + + return block; + } + } + + /// + /// Udp数据处理适配器测试 + /// + public class UdpDataAdapterTester : IDisposable + { + private readonly IntelligentDataQueue asyncBytes; + private UdpDataHandlingAdapter adapter; + private int count; + private bool dispose; + private int expectedCount; + private Action receivedCallBack; + private Stopwatch stopwatch; + private int timeout; + + private UdpDataAdapterTester(int multiThread) + { + this.asyncBytes = new IntelligentDataQueue(1024 * 1024 * 10); + for (int i = 0; i < multiThread; i++) + { + EasyTask.Run(this.BeginSend); + } + } + + /// + /// 获取测试器 + /// + /// 待测试适配器 + /// 并发多线程数量 + /// 收到数据回调 + /// + public static UdpDataAdapterTester CreateTester(UdpDataHandlingAdapter adapter, int multiThread, Action receivedCallBack = default) + { + var tester = new UdpDataAdapterTester(multiThread); + tester.adapter = adapter; + adapter.SendCallBack = tester.SendCallback; + adapter.ReceivedCallBack = tester.OnReceived; + tester.receivedCallBack = receivedCallBack; + return tester; + } + + /// + /// 释放 + /// + public void Dispose() + { + this.dispose = true; + } + + /// + /// 模拟测试运行发送 + /// + /// + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + /// + public TimeSpan Run(byte[] buffer, int offset, int length, int testCount, int expectedCount, int timeout) + { + this.count = 0; + this.expectedCount = expectedCount; + this.timeout = timeout; + this.stopwatch = new Stopwatch(); + this.stopwatch.Start(); + EasyTask.Run(() => + { + for (int i = 0; i < testCount; i++) + { + this.adapter.SendInput(null, buffer, offset, length); + } + }); + if (SpinWait.SpinUntil(() => this.count == this.expectedCount, this.timeout)) + { + this.stopwatch.Stop(); + return this.stopwatch.Elapsed; + } + + throw new TimeoutException(); + } + + /// + /// 模拟发送 + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + public TimeSpan Run(byte[] buffer, int testCount, int expectedCount, int timeout) + { + return this.Run(buffer, 0, buffer.Length, testCount, expectedCount, timeout); + } + + private void BeginSend() + { + while (!this.dispose) + { + if (this.tryGet(out List byteBlocks)) + { + foreach (ByteBlock block in byteBlocks) + { + try + { + this.adapter.ReceivedInput(null, block); + } + finally + { + block.Dispose(); + } + } + } + else + { + Thread.Sleep(1); + } + } + } + + private void OnReceived(EndPoint endPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + this.receivedCallBack?.Invoke(byteBlock, requestInfo); + Interlocked.Increment(ref this.count); + } + + private void SendCallback(EndPoint endPoint, byte[] buffer, int offset, int length) + { + var asyncByte = new QueueDataBytes(new byte[length], 0, length); + Array.Copy(buffer, offset, asyncByte.Buffer, 0, length); + this.asyncBytes.Enqueue(asyncByte); + } + + private bool tryGet(out List byteBlocks) + { + byteBlocks = new List(); + + while (this.asyncBytes.TryDequeue(out QueueDataBytes asyncByte)) + { + var block = new ByteBlock(asyncByte.Length); + block.Write(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + byteBlocks.Add(block); + } + if (byteBlocks.Count > 0) + { + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs.meta new file mode 100644 index 0000000..99191c3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08da8e599969733419560ee0f904537b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp.meta new file mode 100644 index 0000000..e399d10 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2be78369dd3674a409cd586110ac0fed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs new file mode 100644 index 0000000..767247f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 常规UDP数据处理适配器 + /// + public class NormalUdpDataHandlingAdapter : UdpDataHandlingAdapter + { + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + /// + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + this.GoReceived(remoteEndPoint, byteBlock, null); + } + + /// + /// + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + this.GoSend(endPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, IList> transferBytes) + { + int length = 0; + foreach (ArraySegment item in transferBytes) + { + length += item.Count; + } + + if (length > this.MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + using (var byteBlock = new ByteBlock(length)) + { + foreach (ArraySegment item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + this.GoSend(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..66acf5f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11154bd9408318b479f8cf85fdc1f43e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs new file mode 100644 index 0000000..59e29d3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp数据处理适配器 + /// + public abstract class UdpDataHandlingAdapter + { + internal IUdpSession m_owner; + + /// + /// 是否允许发送对象。 + /// + public abstract bool CanSendRequestInfo { get; } + + /// + /// 拼接发送 + /// + public abstract bool CanSplicingSend { get; } + + /// + /// 获取或设置适配器能接收的最大数据包长度。默认1024*1024 Byte。 + /// + public int MaxPackageSize { get; set; } = 1024 * 1024; + + /// + /// 适配器拥有者。 + /// + public IUdpSession Owner => this.m_owner; + + /// + /// 当接收数据处理完成后,回调该函数执行接收 + /// + public Action ReceivedCallBack { get; set; } + + /// + /// 当接收数据处理完成后,回调该函数执行发送 + /// + public Action SendCallBack { get; set; } + + /// + /// 收到数据的切入点,该方法由框架自动调用。 + /// + /// + /// + public void ReceivedInput(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + try + { + this.PreviewReceived(remoteEndPoint, byteBlock); + } + catch (Exception ex) + { + this.OnError(ex.Message); + } + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IRequestInfo requestInfo) + { + this.PreviewSend(requestInfo); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + /// + /// + public void SendInput(EndPoint endPoint, byte[] buffer, int offset, int length) + { + this.PreviewSend(endPoint, buffer, offset, length); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + public void SendInput(EndPoint endPoint, IList> transferBytes) + { + this.PreviewSend(endPoint, transferBytes); + } + + /// + /// 处理已经经过预先处理后的数据 + /// + /// + /// 以二进制形式传递 + /// 以解析实例传递 + protected void GoReceived(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + this.ReceivedCallBack.Invoke(remoteEndPoint, byteBlock, requestInfo); + } + + /// + /// 发送已经经过预先处理后的数据 + /// + /// + /// + /// + /// + protected void GoSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + this.SendCallBack.Invoke(endPoint, buffer, offset, length); + } + + /// + /// 在解析时发生错误。 + /// + /// 错误异常 + /// 是否调用 + /// 是否记录日志 + protected virtual void OnError(string error, bool reset = true, bool log = true) + { + if (reset) + { + this.Reset(); + } + if (log && this.m_owner != null && this.m_owner.Logger != null) + { + this.m_owner.Logger.Error(error); + } + } + + /// + /// 当接收到数据后预先处理数据,然后调用处理数据 + /// + /// + /// + protected abstract void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock); + + /// + /// 当发送数据前预先处理数据 + /// + /// + protected abstract void PreviewSend(IRequestInfo requestInfo); + + /// + /// 当发送数据前预先处理数据 + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected abstract void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 组合发送预处理数据, + /// 当属性SplicingSend实现为True时,系统才会调用该方法。 + /// + /// + /// 代发送数据组合 + protected abstract void PreviewSend(EndPoint endPoint, IList> transferBytes); + + /// + /// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。 + /// + protected abstract void Reset(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs.meta new file mode 100644 index 0000000..df0379c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ac2ba2c8c51f404b9e8421e66fe0c62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs new file mode 100644 index 0000000..dc19651 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UdpKcpPackageAdapter + /// + public class UdpKcpPackageAdapter : NormalUdpDataHandlingAdapter + { + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + base.PreviewReceived(remoteEndPoint, byteBlock); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs.meta new file mode 100644 index 0000000..48bbffe --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b42f8cd9ec3151a4b8df5d66b3ac60dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs new file mode 100644 index 0000000..c33fb6c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs @@ -0,0 +1,388 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UDP数据帧 + /// + public struct UdpFrame + { + /// + /// Crc校验 + /// + public byte[] Crc { get; set; } + + /// + /// 数据 + /// + public byte[] Data { get; set; } + + /// + /// 是否为终结帧 + /// + public bool FIN { get; set; } + + /// + /// 数据ID + /// + public long ID { get; set; } + + /// + /// 帧序号 + /// + public ushort SN { get; set; } + + /// + /// 解析 + /// + /// + /// + /// + /// + public bool Parse(byte[] buffer, int offset, int length) + { + if (length > 11) + { + this.ID = TouchSocketBitConverter.Default.ToInt64(buffer, offset); + this.SN = TouchSocketBitConverter.Default.ToUInt16(buffer, 8 + offset); + this.FIN = buffer[10 + offset].GetBit(7) == 1; + if (this.FIN) + { + if (length > 13) + { + this.Data = new byte[length - 13]; + } + else + { + this.Data = new byte[0]; + } + this.Crc = new byte[2] { buffer[length - 2], buffer[length - 1] }; + } + else + { + this.Data = new byte[length - 11]; + } + + Array.Copy(buffer, 11, this.Data, 0, this.Data.Length); + return true; + } + return false; + } + } + + /// + /// UDP数据包 + /// + [System.Diagnostics.DebuggerDisplay("Count={Count}")] + public class UdpPackage + { + private readonly ConcurrentQueue m_frames; + private readonly Timer m_timer; + private int m_count; + private int m_length; + + private int m_mtu; + + /// + /// 构造函数 + /// + /// + /// + /// + public UdpPackage(long id, int timeout, ConcurrentDictionary revStore) + { + this.ID = id; + this.m_frames = new ConcurrentQueue(); + this.m_timer = new Timer((o) => + { + if (revStore.TryRemove(this.ID, out UdpPackage udpPackage)) + { + udpPackage.m_frames.Clear(); + } + }, null, timeout, Timeout.Infinite); + } + + /// + /// 当前长度 + /// + public int Count => this.m_count; + + /// + /// Crc + /// + public byte[] Crc { get; private set; } + + /// + /// 包唯一标识 + /// + public long ID { get; } + + /// + /// 是否已完成 + /// + public bool IsComplated => this.TotalCount > 0 ? (this.TotalCount == this.m_count ? true : false) : false; + + /// + /// 当前数据长度 + /// + public int Length => this.m_length; + + /// + /// MTU + /// + public int MTU => this.m_mtu + 11; + + /// + /// 总长度,在收到最后一帧之前,为-1。 + /// + public int TotalCount { get; private set; } = -1; + + /// + /// 添加帧 + /// + /// + public void Add(UdpFrame frame) + { + Interlocked.Increment(ref this.m_count); + + if (frame.FIN) + { + this.TotalCount = frame.SN + 1; + this.Crc = frame.Crc; + } + Interlocked.Add(ref this.m_length, frame.Data.Length); + if (frame.SN == 0) + { + this.m_mtu = frame.Data.Length; + } + this.m_frames.Enqueue(frame); + } + + /// + /// 获得数据 + /// + /// + /// + public bool TryGetData(ByteBlock byteBlock) + { + while (this.m_frames.TryDequeue(out UdpFrame frame)) + { + byteBlock.Pos = frame.SN * this.m_mtu; + byteBlock.Write(frame.Data); + } + + if (byteBlock.Len != this.Length) + { + return false; + } + byte[] crc = TouchSocket.Core.Crc.Crc16(byteBlock.Buffer, 0, byteBlock.Len); + if (crc[0] != this.Crc[0] || crc[1] != this.Crc[1]) + { + return false; + } + + return true; + } + } + + /// + /// UDP数据包的适配器 + /// + public class UdpPackageAdapter : UdpDataHandlingAdapter + { + private readonly SnowflakeIDGenerator m_iDGenerator; + private readonly ConcurrentDictionary revStore; + private int m_mtu = 1472; + + /// + /// 构造函数 + /// + public UdpPackageAdapter() + { + this.revStore = new ConcurrentDictionary(); + this.m_iDGenerator = new SnowflakeIDGenerator(4); + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 最大传输单元 + /// + public int MTU + { + get => this.m_mtu + 11; + set => this.m_mtu = value > 11 ? value : 1472; + } + + /// + /// 接收超时时间,默认5000ms + /// + public int Timeout { get; set; } = 5000; + + /// + /// + /// + /// + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + var udpFrame = new UdpFrame(); + if (udpFrame.Parse(byteBlock.Buffer, 0, byteBlock.Len)) + { + UdpPackage udpPackage = this.revStore.GetOrAdd(udpFrame.ID, (i) => new UdpPackage(i, this.Timeout, this.revStore)); + udpPackage.Add(udpFrame); + if (udpPackage.Length > this.MaxPackageSize) + { + this.revStore.TryRemove(udpPackage.ID, out _); + this.m_owner?.Logger.Error("数据长度大于设定的最大值。"); + return; + } + if (udpPackage.IsComplated) + { + if (this.revStore.TryRemove(udpPackage.ID, out _)) + { + using (var block = new ByteBlock(udpPackage.Length)) + { + if (udpPackage.TryGetData(block)) + { + this.GoReceived(remoteEndPoint, block, null); + } + } + } + } + } + } + + /// + /// + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + if (length > this.MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + long id = this.m_iDGenerator.NextID(); + int off = 0; + int surLen = length; + int freeRoom = this.m_mtu - 11; + ushort sn = 0; + /*|********|**|*|n|*/ + /*|********|**|*|**|*/ + while (surLen > 0) + { + byte[] data = new byte[this.m_mtu]; + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, data, 0, 8); + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, data, 8, 2); + if (surLen > freeRoom)//有余 + { + Buffer.BlockCopy(buffer, off, data, 11, freeRoom); + off += freeRoom; + surLen -= freeRoom; + this.GoSend(endPoint, data, 0, this.m_mtu); + } + else if (surLen + 2 <= freeRoom)//结束且能容纳Crc + { + byte flag = 0; + data[10] = flag.SetBit(7, 1);//设置终结帧 + + Buffer.BlockCopy(buffer, off, data, 11, surLen); + Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, data, 11 + surLen, 2); + + this.GoSend(endPoint, data, 0, surLen + 11 + 2); + + off += surLen; + surLen -= surLen; + } + else//结束但不能容纳Crc + { + Buffer.BlockCopy(buffer, off, data, 11, surLen); + this.GoSend(endPoint, data, 0, surLen + 11); + off += surLen; + surLen -= surLen; + + byte[] finData = new byte[13]; + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, finData, 0, 8); + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, finData, 8, 2); + byte flag = 0; + finData[10] = flag.SetBit(7, 1); + Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, finData, 11, 2); + this.GoSend(endPoint, finData, 0, finData.Length); + } + } + } + + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, IList> transferBytes) + { + int length = 0; + foreach (ArraySegment item in transferBytes) + { + length += item.Count; + } + + if (length > this.MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + using (var byteBlock = new ByteBlock(length)) + { + foreach (ArraySegment item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + this.PreviewSend(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs.meta new file mode 100644 index 0000000..5ba020e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b4384f12a07fc348a3af8475c2ea609 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs new file mode 100644 index 0000000..97bc068 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; +using TouchSocket.Sockets; + +/// +/// 显示信息 +/// +/// +/// +public delegate void MessageEventHandler(TClient client, MsgEventArgs e); + +/// +/// 普通通知 +/// +/// +/// +/// +public delegate void TouchSocketEventHandler(TClient client, TouchSocketEventArgs e); + +/// +/// ID修改通知 +/// +/// +/// +/// +public delegate void IDChangedEventHandler(TClient client, IDChangedEventArgs e); + +/// +/// Connecting +/// +/// +/// +/// +public delegate void ConnectingEventHandler(TClient client, ConnectingEventArgs e); + +/// +/// 客户端断开连接 +/// +/// +/// +/// +public delegate void DisconnectEventHandler(TClient client, DisconnectEventArgs e); + +/// +/// 正在连接事件 +/// +/// +/// +/// +public delegate void OperationEventHandler(TClient client, OperationEventArgs e); + +/// +/// 插件数据 +/// +/// +/// +public delegate void PluginReceivedEventHandler(TClient client, ReceivedDataEventArgs e); + +/// +/// 普通数据 +/// +/// +/// +/// +public delegate void ReceivedEventHandler(TClient client, ByteBlock byteBlock, IRequestInfo requestInfo); + +/// +/// UDP接收 +/// +/// +/// +/// +public delegate void UdpReceivedEventHandler(EndPoint endpoint, ByteBlock byteBlock, IRequestInfo requestInfo); \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs.meta new file mode 100644 index 0000000..a8474e9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/DelegateCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 39d2451c1c2497342a172fc32592fc4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum.meta new file mode 100644 index 0000000..78a645b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32d34825c7e39a549b3551df52237e20 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs new file mode 100644 index 0000000..a35f9e3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 检查清理类型 + /// + public enum CheckClearType + { + /// + /// 仅统计发送 + /// + OnlySend, + + /// + /// 仅统计接收 + /// + OnlyReceive, + + /// + /// 全部 + /// + All + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs.meta new file mode 100644 index 0000000..8676137 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/CheckClearType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cefd2d9310185bb44b40861cf3208d7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs new file mode 100644 index 0000000..4a6b6ef --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 过滤结果 + /// + public enum FilterResult + { + /// + /// 缓存后续所有数据。 + /// + Cache, + + /// + /// 操作成功 + /// + Success, + + /// + /// 继续操作,一般原因是本次数据有部分无效,但已经调整了属性,所以继续后续解析。 + /// 或者想放弃当前数据的操作,直接设置相等即可。 + /// + GoOn + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs.meta new file mode 100644 index 0000000..83943f7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FilterResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d2cf42ece360924ea95beff630ea759 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs new file mode 100644 index 0000000..5a9a051 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 固定包头类型 + /// + public enum FixedHeaderType : byte + { + /// + /// 以1Byte标识长度,最长接收255 + /// + Byte = 1, + + /// + /// 以2Byte标识长度,最长接收65535 + /// + Ushort = 2, + + /// + /// 以4Byte标识长度,最长接收2147483647 + /// + Int = 4 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs.meta new file mode 100644 index 0000000..7dcd66e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/FixedHeaderType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cca9964a48740ee42b3d610d6df2fa70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs new file mode 100644 index 0000000..61f858e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 接收类型 + /// + public enum ReceiveType : byte + { + /// + /// 该模式下会自动接收数据,然后主动触发。 + /// + Auto, + + /// + /// 在该模式下,不会投递接收申请,用户可通过,获取到流以后,自己处理接收。 + /// 注意:连接端不会感知主动断开 + /// + None + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs.meta new file mode 100644 index 0000000..9254740 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ReceiveType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9249e4f04ccb0154e8f135ee3db2c96e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs new file mode 100644 index 0000000..57206b9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 服务器状态 + /// + public enum ServerState + { + /// + /// 无状态,指示为初建 + /// + None, + + /// + /// 正在运行 + /// + Running, + + /// + /// 运行遇到异常 + /// + Exception, + + /// + /// 已停止 + /// + Stopped, + + /// + /// 已释放 + /// + Disposed + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs.meta new file mode 100644 index 0000000..decffdc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Enum/ServerState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b738978f477bf847abe38eb9955f677 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs.meta new file mode 100644 index 0000000..fb1b494 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12b9c90678a54d6458578cab6285630a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs new file mode 100644 index 0000000..07c1821 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 字节事件 + /// + public class ByteBlockEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + public ByteBlockEventArgs(ByteBlock byteBlock) + { + ByteBlock = byteBlock; + } + + /// + /// 数据块 + /// + public ByteBlock ByteBlock { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs.meta new file mode 100644 index 0000000..4302c85 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6fe0e4cb6aa33114ea7101a3338b5602 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs new file mode 100644 index 0000000..1ebcd57 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 字节事件 + /// + public class BytesEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public BytesEventArgs(byte[] data) + { + ReceivedDataBytes = data; + } + + /// + /// 字节数组 + /// + public byte[] ReceivedDataBytes { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs.meta new file mode 100644 index 0000000..08b195e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d59a72e928685d642bcce158bbb73689 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs new file mode 100644 index 0000000..fa7c749 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ConfigEventArgs + /// + public class ConfigEventArgs : TouchSocketEventArgs + { + /// + /// 实例化2ConfigEventArgs + /// + /// + public ConfigEventArgs(TouchSocketConfig config) + { + Config = config; + } + + /// + /// 具体配置 + /// + public TouchSocketConfig Config { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs.meta new file mode 100644 index 0000000..065775c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ba92cbcba602e244a85b996d4c47114 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs new file mode 100644 index 0000000..295c2d7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// ClientConnectingEventArgs + /// + [Obsolete("此类已被弃用,请使用ConnectingEventArgs代替", true)] + public class ClientConnectingEventArgs : OperationEventArgs + { + + } + /// + /// 客户端连接事件。 + /// + public class ConnectingEventArgs : OperationEventArgs + { + private readonly Socket socket; + + /// + /// 构造函数 + /// + /// + public ConnectingEventArgs(Socket socket) + { + this.socket = socket; + } + + /// + /// 新初始化的通信器 + /// + public Socket Socket => socket; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs.meta new file mode 100644 index 0000000..ffe61c1 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 067ff574ddcbc3f468d0e95241c39d22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs new file mode 100644 index 0000000..90cde6c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 断开连接事件参数 + /// + public class DisconnectEventArgs : MsgEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public DisconnectEventArgs(bool manual, string mes) : base(mes) + { + Manual = manual; + } + + /// + /// 是否为主动行为。 + /// + public bool Manual { get; private set; } + } + + /// + /// ClientDisconnectedEventArgs + /// + [Obsolete("该类型已被弃用,请使用DisconnectEventArgs替代。", true)] + public class ClientDisconnectedEventArgs : MsgEventArgs + { + + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs.meta new file mode 100644 index 0000000..8fad8dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2823b80a77b3eea48b6885dfd623cd8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs new file mode 100644 index 0000000..ad266e7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// IDChangedEventArgs + /// + public class IDChangedEventArgs : TouchSocketEventArgs + { + /// + /// IDChangedEventArgs + /// + /// + /// + public IDChangedEventArgs(string oldID, string newID) + { + OldID = oldID; + NewID = newID; + } + + /// + /// 旧ID + /// + public string OldID { get; private set; } + + /// + /// 新ID + /// + public string NewID { get; private set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs.meta new file mode 100644 index 0000000..50d20da --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3fe77e7c88fa0874c89fb3b700ae8d9e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs new file mode 100644 index 0000000..c8f00af --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 消息事件 + /// + public class MsgEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public MsgEventArgs(string mes) + { + Message = mes; + } + + /// + /// 构造函数 + /// + public MsgEventArgs() + { + } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs.meta new file mode 100644 index 0000000..abdee84 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e63c8fc1e4dd7d41a95517b31e5df96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs new file mode 100644 index 0000000..990d3ca --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ClientOperationEventArgs + /// + [Obsolete("此类已被弃用,请使用OperationEventArgs代替", true)] + public class ClientOperationEventArgs : TouchSocketEventArgs + { + + } + /// + /// Client消息操作事件 + /// + public class OperationEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + public OperationEventArgs() + { + IsPermitOperation = true; + } + + /// + /// 客户端ID + /// + public string ID { get; set; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs.meta new file mode 100644 index 0000000..d3dd998 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f658eceda65dfb243867f62c94b637da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs new file mode 100644 index 0000000..57c74d3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 插件处理事件 + /// + public class ReceivedDataEventArgs : ByteBlockEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public ReceivedDataEventArgs(ByteBlock byteBlock, IRequestInfo requestInfo) : base(byteBlock) + { + RequestInfo = requestInfo; + } + + /// + /// 对象载体 + /// + public IRequestInfo RequestInfo { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs.meta new file mode 100644 index 0000000..ff3ca4a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1ea3a40a3e585c49b84b2f5390a2b01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs new file mode 100644 index 0000000..e3ec471 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 发送事件 + /// + public class SendingEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public SendingEventArgs(byte[] buffer, int offset, int length) + { + Buffer = buffer; + Offset = offset; + Length = length; + IsPermitOperation = true; + } + + /// + /// 数据缓存区,该属性获取来自于内存池,所以最好不要引用该对象,可以同步使用该对象 + /// + public byte[] Buffer { get; } + + /// + /// 缓存偏移 + /// + public int Offset { get; } + + /// + /// 数据长度 + /// + public int Length { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs.meta new file mode 100644 index 0000000..f1cd38c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aeed9c5b8bad85b4bb764bf542b83fd3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs new file mode 100644 index 0000000..0f69376 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器状态事件参数 + /// + public class ServiceStateEventArgs: MsgEventArgs + { + /// + /// 服务器状态事件参数 + /// + /// + /// + public ServiceStateEventArgs(ServerState serverState,Exception exception) + { + ServerState = serverState; + Exception = exception; + } + + /// + /// 服务器状态 + /// + public ServerState ServerState { get; } + + /// + /// 异常类 + /// + public Exception Exception { get; } + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs.meta new file mode 100644 index 0000000..a3dbec2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ab86b39b542e944abe30487c9576d5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs new file mode 100644 index 0000000..b836dca --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp接收消息 + /// + public class UdpReceivedDataEventArgs : ReceivedDataEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public UdpReceivedDataEventArgs(EndPoint endPoint, ByteBlock byteBlock, IRequestInfo requestInfo) : base(byteBlock, requestInfo) + { + EndPoint = endPoint; + } + + /// + /// 接收终结点 + /// + public EndPoint EndPoint { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs.meta new file mode 100644 index 0000000..31bb505 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6383061f377816d418f38ddb84b03d8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions.meta new file mode 100644 index 0000000..4e6c01c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 758ed09e4681cdb468fe86d484e8ffac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs new file mode 100644 index 0000000..9457e75 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 没有找到ID对应的客户端 + /// + [Serializable] + public class ClientNotFindException : Exception + { + /// + /// 构造函数 + /// + public ClientNotFindException() + { } + + /// + /// 构造函数 + /// + /// + public ClientNotFindException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public ClientNotFindException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected ClientNotFindException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs.meta new file mode 100644 index 0000000..a09cf99 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb2baa8946fed1e4bb56286b4be15f2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs new file mode 100644 index 0000000..b9e0098 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 未连接异常 + /// + [Serializable] + public class NotConnectedException : Exception + { + /// + /// 构造函数 + /// + public NotConnectedException() + { } + + /// + /// 构造函数 + /// + /// + public NotConnectedException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public NotConnectedException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected NotConnectedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs.meta new file mode 100644 index 0000000..26a7080 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/NotConnectedException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd71847080edda44db426f786266106e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs new file mode 100644 index 0000000..f196183 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 超长异常 + /// + [Serializable] + public class OverlengthException : Exception + { + /// + /// 构造函数 + /// + public OverlengthException() + { } + + /// + /// 构造函数 + /// + /// + public OverlengthException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public OverlengthException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected OverlengthException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs.meta new file mode 100644 index 0000000..5a15eb3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Exceptions/OverlengthException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3752b1063bc7d945b158e6e4ad12ad5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions.meta new file mode 100644 index 0000000..1025db8 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2a8b7e593bde1a4bbc259b80486b1dd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs new file mode 100644 index 0000000..cadb918 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端扩展类 + /// + public static class ClientExtension + { + /// + /// 获取相关信息。格式: + ///IPPort=IP:Port,ID=id,Protocol=Protocol + /// + /// + /// + /// + public static string GetInfo(this T client) where T : ISocketClient + { + return $"IP&Port={client.IP}:{client.Port},ID={client.ID},Protocol={client.Protocol}"; + } + + /// + /// 获取服务器中,除自身以外的所有客户端id + /// + /// + /// + /// + public static IEnumerable GetOtherIDs(this T client) where T : ISocketClient + { + return client.Service.GetIDs().Where(id => id != client.ID); + } + + /// + /// 获取最后活动时间。即的最近值。 + /// + /// + /// + /// + public static DateTime GetLastActiveTime(this T client) where T : IClient + { + return client.LastSendTime > client.LastReceivedTime ? client.LastSendTime : client.LastReceivedTime; + } + + /// + /// 安全性发送关闭报文 + /// + /// + /// + /// + public static bool TryShutdown(this T client, SocketShutdown how = SocketShutdown.Both) where T : ITcpClientBase + { + try + { + if (!client.MainSocket.Connected) + { + return false; + } + client?.MainSocket?.Shutdown(how); + return true; + } + catch + { + } + + return false; + } + + /// + /// 安全性关闭。不会抛出异常。 + /// + /// + /// + /// + public static void SafeClose(this T client, string msg) where T : ITcpClientBase + { + try + { + client.Close(msg); + } + catch + { + } + } + + /// + /// 获取IP和端口。 + /// + /// + /// + /// + public static string GetIPPort(this T client) where T : ITcpClientBase + { + return $"{client.IP}:{client.Port}"; + } + + #region 连接 + + /// + /// 尝试连接。不会抛出异常。 + /// + /// + /// + /// + /// + public static Result TryConnect(this TClient client, int timeout = 5000) where TClient : ITcpClient + { + try + { + client.Connect(timeout); + return new Result(ResultCode.Success); + } + catch (Exception ex) + { + return new Result(ResultCode.Exception, ex.Message); + } + } + + /// + /// 尝试连接。不会抛出异常。 + /// + /// + /// + /// + /// + public static async Task TryConnectAsync(this TClient client, int timeout = 5000) where TClient : ITcpClient + { + try + { + await client.ConnectAsync(timeout); + return new Result(ResultCode.Success); + } + catch (Exception ex) + { + return new Result(ResultCode.Exception, ex.Message); + } + } + + #endregion 连接 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs.meta new file mode 100644 index 0000000..d00bcd2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/ClientExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9e94468c96070442930633101ef1f81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs new file mode 100644 index 0000000..b2b410e --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs @@ -0,0 +1,353 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// SenderExtension + /// + public static class SenderExtension + { + #region ISend + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void Send(this TClient client, byte[] buffer) where TClient : ISender + { + client.Send(buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void Send(this TClient client, ByteBlock byteBlock) where TClient : ISender + { + client.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + public static void Send(this TClient client, string value) where TClient : ISender + { + client.Send(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + public static Task SendAsync(this TClient client, byte[] buffer) where TClient : ISender + { + return client.SendAsync(buffer, 0, buffer.Length); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string value) where TClient : ISender + { + return client.SendAsync(Encoding.UTF8.GetBytes(value)); + } + + #endregion ISend + + #region IDefaultSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, string value) where TClient : IDefaultSender + { + client.DefaultSend(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, byte[] buffer) where TClient : IDefaultSender + { + client.DefaultSend(buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, ByteBlock byteBlock) where TClient : IDefaultSender + { + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, string value) where TClient : IDefaultSender + { + return client.DefaultSendAsync(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, byte[] buffer) where TClient : IDefaultSender + { + return client.DefaultSendAsync(buffer, 0, buffer.Length); + } + + #endregion IDefaultSender + + #region IIDSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, string value) where TClient : IIDSender + { + client.Send(id, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, byte[] buffer) where TClient : IIDSender + { + client.Send(id, buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, ByteBlock byteBlock) where TClient : IIDSender + { + client.Send(id, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string id, string value) where TClient : IIDSender + { + return client.SendAsync(id, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string id, byte[] buffer) where TClient : IIDSender + { + return client.SendAsync(id, buffer, 0, buffer.Length); + } + + #endregion IIDSender + + #region IUdpDefaultSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void DefaultSend(this TClient client, EndPoint endPoint, string value) where TClient : IUdpDefaultSender + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + client.DefaultSend(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void DefaultSend(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpDefaultSender + { + client.DefaultSend(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, string value) where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// 数据缓存区 + /// 发送数据超长 + /// 其他异常 + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// + /// 发送数据超长 + /// 其他异常 + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, ByteBlock byteBlock) + where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + + #endregion IUdpDefaultSender + + #region IUdpClientSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, EndPoint endPoint, string value) where TClient : IUdpClientSender + { + client.Send(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void Send(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpClientSender + { + client.Send(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void Send(this TClient client, EndPoint endPoint, ByteBlock byteBlock) + where TClient : IUdpClientSender + { + client.Send(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, EndPoint endPoint, string value) where TClient : IUdpClientSender + { + return client.SendAsync(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据缓存区 + /// 发送数据超长 + /// 其他异常 + public static Task SendAsync(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpClientSender + { + return client.SendAsync(endPoint, buffer, 0, buffer.Length); + } + + #endregion IUdpClientSender + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs.meta new file mode 100644 index 0000000..cfb6c7d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SenderExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 615c725c2d6b86b4595c64e313be885e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs new file mode 100644 index 0000000..fb621ab --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// SocketExtension + /// + public static class SocketExtension + { + /// + /// 会使用同步锁,保证所有数据上缓存区。 + /// + /// + /// + /// + /// + public static void AbsoluteSend(this Socket socket, byte[] buffer, int offset, int length) + { + lock (socket) + { + while (length > 0) + { + int r = socket.Send(buffer, offset, length, SocketFlags.None); + if (r == 0 && length > 0) + { + throw new Exception("发送数据不完全"); + } + offset += r; + length -= r; + } + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs.meta new file mode 100644 index 0000000..3c007b6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b0922b02a5d8434cb857e4e34fab5db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs new file mode 100644 index 0000000..17fa303 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Sockets; + +namespace TouchSocket.Core +{ + /// + /// IPluginsManagerExtension + /// + public static class SocketPluginsManagerExtension + { + /// + /// 使用断线重连。 + /// 该效果仅客户端在完成首次连接,且为被动断开时有效。 + /// + /// + /// 成功回调函数 + /// 尝试重连次数,设为-1时则永远尝试连接 + /// 是否输出日志。 + /// 失败时,停留时间 + /// + public static IPluginsManager UseReconnection(this IPluginsManager pluginsManager, int tryCount = 10, + bool printLog = false, int sleepTime = 1000, Action successCallback = null) + { + bool first = true; + var reconnectionPlugin = new ReconnectionPlugin(client => + { + int tryT = tryCount; + while (tryCount < 0 || tryT-- > 0) + { + try + { + if (client.Online) + { + return true; + } + else + { + if (first) Thread.Sleep(1000); + first = false; + client.Connect(); + first = true; + } + successCallback?.Invoke(client); + return true; + } + catch (Exception ex) + { + if (printLog) + { + client.Logger.Log(LogType.Error, client, "断线重连失败。", ex); + } + Thread.Sleep(sleepTime); + } + } + return true; + }); + + pluginsManager.Add(reconnectionPlugin); + return pluginsManager; + } + + /// + /// 检查连接客户端活性插件。 + /// 当在设置的周期内,没有接收/发送任何数据,则判定该客户端掉线。执行清理。默认配置:60秒为一个周期,同时检测发送和接收。 + /// 仅服务器适用。 + /// + /// + /// + public static CheckClearPlugin UseCheckClear(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + + /// + /// 使用断线重连。 + /// 该效果仅客户端在完成首次连接,且为被动断开时有效。 + /// + /// + /// 失败时间隔时间 + /// 失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回false,则终止尝试下次连接。 + /// 成功连接时回调。 + /// + public static IPluginsManager UseReconnection(this IPluginsManager pluginsManager, int sleepTime, + Func failCallback, + Action successCallback) + { + bool first = true; + var reconnectionPlugin = new ReconnectionPlugin(client => + { + int tryT = 0; + while (true) + { + try + { + if (client.Online) + { + return true; + } + else + { + if (first) Thread.Sleep(1000); + first = false; + client.Connect(); + first = true; + } + + successCallback?.Invoke(client); + return true; + } + catch (Exception ex) + { + Thread.Sleep(sleepTime); + if (failCallback?.Invoke(client, ++tryT, ex) != true) + { + return true; + } + } + } + }); + + pluginsManager.Add(reconnectionPlugin); + return pluginsManager; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs.meta new file mode 100644 index 0000000..452898d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fff859eb3ba21e049a6aaaa4a6fd7ba7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface.meta new file mode 100644 index 0000000..d6af2df --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf47a72df11b6bc46839a32c45984555 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs new file mode 100644 index 0000000..f3c149f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 终端接口 + /// + public interface IClient : IDependencyObject, IDisposable + { + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + Func OnHandleReceivedData { get; set; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 终端协议 + /// + Protocol Protocol { get; set; } + + /// + /// 简单IOC容器 + /// + IContainer Container { get; } + + /// + /// 最后一次接收到数据的时间 + /// + DateTime LastReceivedTime { get; } + + /// + /// 最后一次发送数据的时间 + /// + DateTime LastSendTime { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs.meta new file mode 100644 index 0000000..ef7c0a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 482d60ba6c6c70347b8310f909e8097e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs new file mode 100644 index 0000000..c93cf80 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// INATSocketClient + /// + public interface INATSocketClient : ISocketClient + { + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + ITcpClient AddTargetClient(TouchSocketConfig config, Action setupAction = null); + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + Task AddTargetClientAsync(TouchSocketConfig config, Action setupAction = null); + + /// + /// 获取所有目标客户端 + /// + /// + ITcpClient[] GetTargetClients(); + + /// + /// 发送数据到全部转发端。 + /// + /// + /// + /// + void SendToTargetClient(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs.meta new file mode 100644 index 0000000..0600f4b --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/INATSocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3dfc6f1606bddef438c0ae3bf6d113c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs new file mode 100644 index 0000000..b2a180a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 请求解析对象接口。 + ///此处接口设计借鉴SuperSocket,只为大家更好理解 + /// + public interface IRequestInfo + { + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs.meta new file mode 100644 index 0000000..0999e85 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IRequestInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4064b1da34836741aaabd54923fd886 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender.meta new file mode 100644 index 0000000..a0e2c1c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 78fe6186bc86bc24b8c2bbcfff5ee0a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs new file mode 100644 index 0000000..a154a79 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端发送接口 + /// + public interface IClientSender : ISender, IRequsetInfoSender + { + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(IList> transferBytes); + + /// + /// 异步组合发送数据。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(IList> transferBytes); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs.meta new file mode 100644 index 0000000..efb8593 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IClientSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7ce4dc4a60bf9c41824762186395f51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs new file mode 100644 index 0000000..6e1fd6f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有直接发送功能 + /// + public interface IDefaultSender + { + /// + /// 绕过适配器,直接发送字节流 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void DefaultSend(byte[] buffer, int offset, int length); + + /// + /// 绕过适配器,直接发送字节流 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task DefaultSendAsync(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs.meta new file mode 100644 index 0000000..e140311 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b82909f553967740be31c3286b78f15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs new file mode 100644 index 0000000..6b167c2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// IIDRequsetInfoSender + /// + public interface IIDRequsetInfoSender + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(string id, IRequestInfo requestInfo); + + /// + /// 异步发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(string id, IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs.meta new file mode 100644 index 0000000..22011c4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9b3e3141c6ecf24bbd9db9b2dce73b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs new file mode 100644 index 0000000..cec5008 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 通过ID发送 + /// + public interface IIDSender + { + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string id, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string id, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据对象 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string id, IRequestInfo requestInfo); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据对象 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string id, IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs.meta new file mode 100644 index 0000000..f9c4654 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IIDSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 580aef2716612054fbfbbe9bc18d0774 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs new file mode 100644 index 0000000..6734f41 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// IRequsetInfoSend + /// + public interface IRequsetInfoSender + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(IRequestInfo requestInfo); + + /// + /// 异步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs.meta new file mode 100644 index 0000000..d42f5d0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b2abfe0e2610f3458061e09c50035f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs new file mode 100644 index 0000000..0a77a58 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有发送功能的接口 + /// + public interface ISender : ISenderBase + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(byte[] buffer, int offset, int length); + + /// + /// 异步发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs.meta new file mode 100644 index 0000000..8d5deb2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 708c41c0a94a3764a9e63a1958a5797e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs new file mode 100644 index 0000000..6b6ca33 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 具有发送动作的基类。 + /// + public interface ISenderBase + { + /// + /// 表示对象能否顺利执行发送操作。 + /// 由于高并发,当该值为True时,也不一定完全能执行。 + /// + bool CanSend { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs.meta new file mode 100644 index 0000000..17dc6d3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32cb06c04722a844b857f2bc0e29bbe0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs new file mode 100644 index 0000000..22a6c5a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有Udp终结点的发送 + /// + public interface IUdpClientSender : ISender + { + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(EndPoint endPoint, IList> transferBytes); + + /// + /// 异步组合发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(EndPoint endPoint, IList> transferBytes); + + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// + /// + /// + /// 发送数据超长 + /// 其他异常 + void Send(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 异步组合发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// + /// + /// + /// 发送数据超长 + /// 其他异常 + Task SendAsync(EndPoint endPoint, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs.meta new file mode 100644 index 0000000..f288fd3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f09af82d3abe434d9c647b5c6a5e009 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs new file mode 100644 index 0000000..60b6eb3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有直接发送功能 + /// + public interface IUdpDefaultSender : ISenderBase + { + /// + /// 绕过适配器,直接发送字节流 + /// + /// 目的终结点 + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void DefaultSend(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 绕过适配器,直接发送字节流 + /// + /// 目的终结点 + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task DefaultSendAsync(EndPoint endPoint, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs.meta new file mode 100644 index 0000000..74ca3e9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53c957ef7111f92419e44e897f5c1ab9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs new file mode 100644 index 0000000..07f2c8c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 发送等待接口 + /// + public interface IWaitSender : ISenderBase + { + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs.meta new file mode 100644 index 0000000..b52a994 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8bb1f84debf0a14a8241af7c1d07aa3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs new file mode 100644 index 0000000..b26ee4a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器接口 + /// + public interface IService : IDisposable + { + /// + /// 服务器状态 + /// + ServerState ServerState { get; } + + /// + /// 获取服务器配置 + /// + TouchSocketConfig Config { get; } + + /// + /// 名称 + /// + string ServerName { get; } + + /// + /// 配置服务器 + /// + /// 配置 + /// + /// 设置的服务实例 + IService Setup(TouchSocketConfig serverConfig); + + /// + /// 配置服务器 + /// + /// + /// + /// 设置的服务实例 + IService Setup(int port); + + /// + /// 启动 + /// + /// + /// + /// + /// 设置的服务实例 + IService Start(); + + /// + /// 停止 + /// + /// + /// 设置的服务实例 + IService Stop(); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs.meta new file mode 100644 index 0000000..2368be0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 702a5542a086b0d48b992a5d2c5273a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs new file mode 100644 index 0000000..440ca46 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Socket基接口 + /// + public interface ISocket : IDisposable + { + /// + /// 数据交互缓存池限制 + /// + int BufferLength { get; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs.meta new file mode 100644 index 0000000..502c61a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b140f650f1321d54baa1938359e066f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs new file mode 100644 index 0000000..ec88d71 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 服务器辅助类接口 + /// + public interface ISocketClient : ITcpClientBase, IClientSender, IIDSender, IIDRequsetInfoSender + { + /// + /// 重新设置ID + /// + /// + void ResetID(string newID); + + /// + /// 用于索引的ID + /// + string ID { get; } + + /// + /// 包含此辅助类的主服务器类 + /// + TcpServiceBase Service { get; } + + /// + /// 接收此客户端的服务器IP地址 + /// + string ServiceIP { get; } + + /// + /// 接收此客户端的服务器端口 + /// + int ServicePort { get; } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs.meta new file mode 100644 index 0000000..dcacc30 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ISocketClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4aed091dba8e3c40a5c912a5c7b7ced +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs new file mode 100644 index 0000000..4635b11 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP客户端终端接口 + /// + public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject + { + /// + /// 成功连接到服务器 + /// + MessageEventHandler Connected { get; set; } + + /// + /// 准备连接的时候 + /// + ConnectingEventHandler Connecting { get; set; } + + /// + /// 远程IPHost。 + /// + IPHost RemoteIPHost { get; } + + /// + /// 连接服务器 + /// + /// + /// + ITcpClient Connect(int timeout = 5000); + + /// + /// 异步连接服务器 + /// + /// + /// + Task ConnectAsync(int timeout = 5000); + + /// + /// 配置服务器 + /// + /// + /// + ITcpClient Setup(TouchSocketConfig config); + + /// + /// 配置服务器 + /// + /// + /// + ITcpClient Setup(string ipHost); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs.meta new file mode 100644 index 0000000..98f2cf7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7afde5aec3520d458759e53e1d5b122 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs new file mode 100644 index 0000000..067e3b9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP终端基础接口。 + /// + /// 注意:该接口并不仅表示客户端。也实现了该接口。 + /// + /// + public interface ITcpClientBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender + { + /// + /// 缓存池大小 + /// + int BufferLength { get; } + + /// + /// 是否允许自由调用进行赋值。 + /// + bool CanSetDataHandlingAdapter { get; } + + /// + /// 客户端配置 + /// + TouchSocketConfig Config { get; } + + /// + /// 数据处理适配器 + /// + DataHandlingAdapter DataHandlingAdapter { get; } + + /// + /// 断开连接 + /// + DisconnectEventHandler Disconnected { get; set; } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + DisconnectEventHandler Disconnecting { get; set; } + /// + /// IP地址 + /// + string IP { get; } + + /// + /// 表示是否为客户端。 + /// + bool IsClient { get; } + /// + /// 主通信器 + /// + Socket MainSocket { get; } + + /// + /// 判断是否在线 + /// 该属性仅表示TCP状态是否在线 + /// + bool Online { get; } + + /// + /// 端口号 + /// + int Port { get; } + + /// + /// 接收模式 + /// + public ReceiveType ReceiveType { get; } + + /// + /// 使用Ssl加密 + /// + bool UseSsl { get; } + + + /// + /// 中断终端 + /// + void Close(); + + /// + /// 中断终端,传递中断消息 + /// + /// + void Close(string msg); + + /// + /// 获取流,在正常模式下为,在Ssl模式下为。 + /// + /// + Stream GetStream(); + + /// + /// 设置数据处理适配器 + /// + /// + void SetDataHandlingAdapter(DataHandlingAdapter adapter); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs.meta new file mode 100644 index 0000000..bafe3a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpClientBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac1eb6409d76c414e8dfd343e4fbeee8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs new file mode 100644 index 0000000..41f7b4c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP系列服务器接口 + /// + public interface ITcpService : ITcpService where TClient : ISocketClient + { + /// + /// 用户连接完成 + /// + TouchSocketEventHandler Connected { get; set; } + + /// + /// 有用户连接的时候 + /// + OperationEventHandler Connecting { get; set; } + + /// + /// 有用户断开连接 + /// + DisconnectEventHandler Disconnected { get; set; } + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + bool TryGetSocketClient(string id, out TClient socketClient); + } + + /// + /// TCP服务器接口 + /// + public interface ITcpService : IService, IIDSender, IIDRequsetInfoSender, IPluginObject + { + /// + /// 当前在线客户端数量 + /// + int Count { get; } + + /// + /// 获取默认新ID。 + /// + Func GetDefaultNewID { get; } + + /// + /// 获取最大可连接数 + /// + int MaxCount { get; } + + /// + /// 网络监听集合 + /// + NetworkMonitor[] Monitors { get; } + + /// + /// 获取当前连接的所有客户端 + /// + SocketClientCollection SocketClients { get; } + + /// + /// 使用Ssl加密 + /// + bool UseSsl { get; } + + /// + /// 清理当前已连接的所有客户端 + /// + void Clear(); + + /// + /// 获取当前在线的所有ID集合 + /// + /// + string[] GetIDs(); + + /// + /// 重置ID + /// + /// + /// + /// + /// + void ResetID(string oldID, string newID); + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + bool SocketClientExist(string id); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs.meta new file mode 100644 index 0000000..83f8769 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/ITcpService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e1ecadff526eb54a8aab4c0e19cddca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs new file mode 100644 index 0000000..71a10ba --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UDP会话 + /// + public interface IUdpSession : IService, IClient, IClientSender, IUdpClientSender, IDefaultSender, IUdpDefaultSender + { + /// + /// 插件管理器 + /// + IPluginsManager PluginsManager { get; } + + /// + /// 缓存池大小 + /// + int BufferLength { get; } + + /// + /// 是否允许自由调用进行赋值。 + /// + bool CanSetDataHandlingAdapter { get; } + + /// + /// 数据处理适配器 + /// + UdpDataHandlingAdapter DataHandlingAdapter { get; } + + /// + /// 设置数据处理适配器 + /// + /// + void SetDataHandlingAdapter(UdpDataHandlingAdapter adapter); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs.meta new file mode 100644 index 0000000..004f0a6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/IUdpSession.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3d16f3c90f508a4ea4b2a567f19c3c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins.meta new file mode 100644 index 0000000..f1e912c --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61128c6439341494dae891fb08148a78 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs new file mode 100644 index 0000000..eb2a3c9 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 当配置Config时触发。 + /// + public interface IConfigPlugin : IPlugin + { + /// + /// 当载入配置时 + /// + /// + /// + [AsyncRaiser] + void OnLoadingConfig(object sender, ConfigEventArgs e); + + /// + /// 当载入配置时 + /// + /// + /// + Task OnLoadingConfigAsync(object sender, ConfigEventArgs e); + + /// + /// 当完成配置载入时 + /// + /// + /// + [AsyncRaiser] + void OnLoadedConfig(object sender, ConfigEventArgs e); + + /// + /// 当完成配置载入时 + /// + /// + /// + /// + Task OnLoadedConfigAsync(object sender, ConfigEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs.meta new file mode 100644 index 0000000..c7101dd --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da61864babeb5a2469258633d505287a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs new file mode 100644 index 0000000..a9c1ddc --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 具有完成连接动作的插件接口 + /// + public interface IConnectedPlugin:IPlugin + { + /// + /// 客户端连接成功后触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnConnected(object client, TouchSocketEventArgs e); + + /// + /// 客户端连接成功后触发 + /// + /// + /// + /// + Task OnConnectedAsync(object client, TouchSocketEventArgs e); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs.meta new file mode 100644 index 0000000..939aa87 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectedPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87587b02f2524044991d234dc8569cfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs new file mode 100644 index 0000000..d14b791 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 具有预备连接的插件接口 + /// + public interface IConnectingPlugin:IPlugin + { + /// + ///在即将完成连接时触发。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnConnecting(object client, OperationEventArgs e); + + /// + /// 在即将完成连接时触发。 + /// + /// + /// + /// + Task OnConnectingAsync(object client, OperationEventArgs e); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs.meta new file mode 100644 index 0000000..5750c24 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IConnectingPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 051a1e5266ff28b43908b7d981b85ed6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs new file mode 100644 index 0000000..741efce --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 具有断开连接的插件接口 + /// + public interface IDisconnectedPlguin:IPlugin + { + /// + /// 会话断开后触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnDisconnected(object client, DisconnectEventArgs e); + + /// + /// 会话断开后触发 + /// + /// + /// + /// + Task OnDisconnectedAsync(object client, DisconnectEventArgs e); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs.meta new file mode 100644 index 0000000..ab9e818 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectedPlguin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4731611b94dfe54ba07fe242733e476 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs new file mode 100644 index 0000000..b352839 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 具有预断开连接插件接口 + /// + public interface IDisconnectingPlugin:IPlugin + { + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnDisconnecting(object client, DisconnectEventArgs e); + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + /// + Task OnDisconnectingAsync(object client, DisconnectEventArgs e); + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs.meta new file mode 100644 index 0000000..afb964f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IDisconnectingPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4adfdae176c44e8498cfbb11cdf79920 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs new file mode 100644 index 0000000..edd6676 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs @@ -0,0 +1,48 @@ +using TouchSocket.Core; +using System.Threading.Tasks; +using System; + +namespace TouchSocket.Sockets +{ + /// + /// IServicePlugin + /// + public interface IServicePlugin : IPlugin + { + /// + /// 当服务器执行后时。 + /// + /// 注意:此处并不表示服务器成功启动,具体状态请看 + /// + /// + /// + /// + [AsyncRaiser] + void OnStarted(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器执行后时。 + /// + /// 注意:此处并不表示服务器成功启动,具体状态请看 + /// + /// + /// + /// + Task OnStartedAsync(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器调用或者时 + /// + /// + /// + [AsyncRaiser] + void OnStoped(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器调用或者时 + /// + /// + /// + Task OnStopedAsync(object sender, ServiceStateEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs.meta new file mode 100644 index 0000000..d473b88 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84766eed326b21e4bb4a658c7465055e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs new file mode 100644 index 0000000..1bee0ff --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Tcp系插件接口 + /// + public interface ITcpPlugin : IPlugin, IConnectingPlugin, IConnectedPlugin, IDisconnectingPlugin, IDisconnectedPlguin + { + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + [AsyncRaiser] + void OnIDChanged(ITcpClientBase client, IDChangedEventArgs e); + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + /// + Task OnIDChangedAsync(ITcpClientBase client, IDChangedEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + Task OnReceivedDataAsync(ITcpClientBase client, ReceivedDataEventArgs e); + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e); + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// + /// + /// + Task OnReceivingDataAsync(ITcpClientBase client, ByteBlockEventArgs e); + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnSendingData(ITcpClientBase client, SendingEventArgs e); + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// + /// + /// + Task OnSendingDataAsync(ITcpClientBase client, SendingEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs.meta new file mode 100644 index 0000000..ff61264 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e59dd789877a5b5489ede62c4947a526 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs new file mode 100644 index 0000000..4f45139 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp会话插件 + /// + public interface IUdpSessionPlugin : IPlugin + { + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivedData(IUdpSession client, UdpReceivedDataEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + Task OnReceivedDataAsync(IUdpSession client, UdpReceivedDataEventArgs e); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs.meta new file mode 100644 index 0000000..ee832be --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbebd8fdbad060549bc55b35c61f42f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins.meta new file mode 100644 index 0000000..ef684ed --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4623f28cd614e7046bb446673549734e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs new file mode 100644 index 0000000..b28e759 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 检查清理连接插件。服务器适用。 + /// + [SingletonPlugin] + public class CheckClearPlugin : TcpPluginBase + { + private ITcpService m_service; + private Thread m_thread; + + /// + /// 清理统计类型。默认为:。当设置为时, + /// 则只检验发送方向是否有数据流动。没有的话则会断开连接。 + /// + public CheckClearType CheckClearType { get; set; } = CheckClearType.All; + + /// + /// 获取或设置清理无数据交互的Client,默认60秒。 + /// + public TimeSpan Duration { get; set; } = TimeSpan.FromSeconds(60); + + /// + /// 清理统计类型。默认为:。当设置为时, + /// 则只检验发送方向是否有数据流动。没有的话则会断开连接。 + /// + /// + /// + public CheckClearPlugin SetCheckClearType(CheckClearType clearType) + { + CheckClearType = clearType; + return this; + } + + /// + /// 设置清理无数据交互的Client,默认60秒。 + /// + /// + /// + public CheckClearPlugin SetDuration(TimeSpan timeSpan) + { + if (timeSpan == TimeSpan.Zero || timeSpan == TimeSpan.MaxValue || timeSpan == TimeSpan.MinValue) + { + throw new InvalidTimeZoneException("设置的时间必须为有效值。"); + } + Duration = timeSpan; + return this; + } + + /// + protected override void OnLoadedConfig(object sender, ConfigEventArgs e) + { + if (sender is ITcpService service) + { + m_service = service; + m_thread = new Thread(ClearThread); + m_thread.IsBackground = true; + m_thread.Start(); + } + base.OnLoadedConfig(sender, e); + } + + private void ClearThread(object obj) + { + while (true) + { + if (m_service.ServerState == ServerState.Disposed || DisposedValue) + { + return; + } + foreach (var client in m_service.SocketClients.GetClients()) + { + if (CheckClearType == CheckClearType.OnlyReceive) + { + if (DateTime.Now - client.LastReceivedTime > Duration) + { + client.SafeClose("超时无数据Receive交互,主动断开连接"); + } + } + else if (CheckClearType == CheckClearType.OnlySend) + { + if (DateTime.Now - client.LastSendTime > Duration) + { + client.SafeClose("超时无数据Send交互,主动断开连接"); + } + } + else + { + if (DateTime.Now - client.GetLastActiveTime() > Duration) + { + client.SafeClose("超时无数据交互,主动断开连接"); + } + } + } + + Thread.Sleep(1000); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs.meta new file mode 100644 index 0000000..72595c6 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8b36b8c4086fb34392d485868f1e254 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs new file mode 100644 index 0000000..a4a296f --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 重连插件 + /// + [SingletonPlugin] + public sealed class ReconnectionPlugin : TcpPluginBase where TClient : class, ITcpClient + { + private readonly Func m_tryCon; + + /// + /// 初始化一个重连插件 + /// + /// 无论如何,只要返回True,则结束本轮尝试 + public ReconnectionPlugin(Func tryCon) + { + Order = int.MinValue; + m_tryCon = tryCon; + } + + /// + /// + /// + /// + /// + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + base.OnDisconnected(client, e); + + if (client is ITcpClient tcpClient) + { + if (e.Manual) + { + return; + } + EasyTask.Run(() => + { + while (true) + { + try + { + if (m_tryCon.Invoke((TClient)tcpClient)) + { + break; + } + } + catch + { + } + } + }); + } + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs.meta new file mode 100644 index 0000000..69a1e33 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e6eba035846bf9479b4a824db42c684 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs new file mode 100644 index 0000000..696b0df --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ServicePlugin + /// + public class ServicePlugin : PluginBase, IServicePlugin + { + /// + protected virtual void OnStarted(TService sender, ServiceStateEventArgs e) + { + + } + + /// + protected virtual Task OnStartedAsync(TService sender, ServiceStateEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + protected virtual void OnStoped(TService sender, ServiceStateEventArgs e) + { + + } + + /// + protected virtual Task OnStopedAsync(TService sender, ServiceStateEventArgs e) + { + return EasyTask.CompletedTask; + } + + void IServicePlugin.OnStarted(object sender, ServiceStateEventArgs e) + { + this.OnStarted((TService)sender, e); + } + + Task IServicePlugin.OnStartedAsync(object sender, ServiceStateEventArgs e) + { + return this.OnStartedAsync((TService)sender, e); + } + + void IServicePlugin.OnStoped(object sender, ServiceStateEventArgs e) + { + this.OnStoped((TService)sender, e); + } + + Task IServicePlugin.OnStopedAsync(object sender, ServiceStateEventArgs e) + { + return this.OnStopedAsync((TService)sender, e); + } + } + + /// + /// TcpServicePlugin + /// + public class TcpServicePlugin : ServicePlugin + { + + } + + /// + /// UdpServicePlugin + /// + public class UdpServicePlugin : ServicePlugin + { + + } +} diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs.meta new file mode 100644 index 0000000..e998998 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/ServicePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26400908ad5156f469365f6c9098aee4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs new file mode 100644 index 0000000..7d10186 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP命令行插件。 + /// + public abstract class TcpCommandLinePlugin : TcpPluginBase + { + private readonly Dictionary m_pairs = new Dictionary(); + private ILog m_logger; + + /// + /// TCP命令行插件。 + /// + /// + /// + protected TcpCommandLinePlugin(ILog logger) + { + m_logger = logger ?? throw new ArgumentNullException(nameof(logger)); + Converter = new StringConverter(); + var ms = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(a => a.Name.EndsWith("Command")); + foreach (var item in ms) + { + m_pairs.Add(item.Name.Replace("Command", string.Empty), new Method(item)); + } + } + + /// + /// 字符串转换器,默认支持基础类型和Json。可以自定义。 + /// + public StringConverter Converter { get; } + + /// + /// 是否返回执行异常。 + /// + public bool ReturnException { get; set; } = true; + + /// + /// 当有执行异常时,不返回异常。 + /// + /// + public TcpCommandLinePlugin NoReturnException() + { + ReturnException = false; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + try + { + string[] strs = e.ByteBlock.ToString().Split(' '); + if (strs.Length > 0 && m_pairs.TryGetValue(strs[0], out Method method)) + { + var ps = method.Info.GetParameters(); + object[] os = new object[ps.Length]; + int index = 0; + for (int i = 0; i < ps.Length; i++) + { + if (ps[i].ParameterType.IsInterface && typeof(ITcpClientBase).IsAssignableFrom(ps[i].ParameterType)) + { + os[i] = client; + } + else + { + os[i] = Converter.ConvertFrom(strs[index + 1], ps[i].ParameterType); + index++; + } + } + e.Handled = true; + + try + { + object result = method.Invoke(this, os); + if (method.HasReturn) + { + client.Send(Converter.ConvertTo(result)); + } + } + catch (Exception ex) + { + if (ReturnException) + { + client.Send(ex.Message); + } + } + } + } + catch (Exception ex) + { + m_logger.Log(LogType.Error, this, ex.Message, ex); + } + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs.meta new file mode 100644 index 0000000..5702fe2 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 663101a61d673ed43ae8632419882757 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs new file mode 100644 index 0000000..b46ada7 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs @@ -0,0 +1,325 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 插件实现基类 + /// + public abstract class TcpPluginBase : TcpPluginBase + { + } + + /// + /// 插件实现基类 + /// + public abstract class TcpPluginBase : PluginBase, ITcpPlugin, IConfigPlugin + { + void IConnectedPlugin.OnConnected(object client, TouchSocketEventArgs e) + { + OnConnected((TClient)client, e); + } + + Task IConnectedPlugin.OnConnectedAsync(object client, TouchSocketEventArgs e) + { + return OnConnectedAsync((TClient)client, e); + } + + void IConnectingPlugin.OnConnecting(object client, OperationEventArgs e) + { + OnConnecting((TClient)client, e); + } + + Task IConnectingPlugin.OnConnectingAsync(object client, OperationEventArgs e) + { + return OnConnectingAsync((TClient)client, e); + } + + void IDisconnectedPlguin.OnDisconnected(object client, DisconnectEventArgs e) + { + OnDisconnected((TClient)client, e); + } + + Task IDisconnectedPlguin.OnDisconnectedAsync(object client, DisconnectEventArgs e) + { + return OnDisconnectedAsync((TClient)client, e); + } + + void IDisconnectingPlugin.OnDisconnecting(object client, DisconnectEventArgs e) + { + this.OnDisconnecting((TClient)client, e); + } + + Task IDisconnectingPlugin.OnDisconnectingAsync(object client, DisconnectEventArgs e) + { + return this.OnDisconnectingAsync((TClient)client, e); + } + + void ITcpPlugin.OnIDChanged(ITcpClientBase client, IDChangedEventArgs e) + { + OnIDChanged((TClient)client, e); + } + + Task ITcpPlugin.OnIDChangedAsync(ITcpClientBase client, IDChangedEventArgs e) + { + return OnIDChangedAsync((TClient)client, e); + } + + void IConfigPlugin.OnLoadedConfig(object sender, ConfigEventArgs e) + { + OnLoadedConfig(sender, e); + } + + Task IConfigPlugin.OnLoadedConfigAsync(object sender, ConfigEventArgs e) + { + return OnLoadedConfigAsync(sender, e); + } + + void IConfigPlugin.OnLoadingConfig(object sender, ConfigEventArgs e) + { + OnLoadingConfig(sender, e); + } + + Task IConfigPlugin.OnLoadingConfigAsync(object sender, ConfigEventArgs e) + { + return OnLoadingConfigAsync(sender, e); + } + + void ITcpPlugin.OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + OnReceivedData((TClient)client, e); + } + + Task ITcpPlugin.OnReceivedDataAsync(ITcpClientBase client, ReceivedDataEventArgs e) + { + return OnReceivedDataAsync((TClient)client, e); + } + + void ITcpPlugin.OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e) + { + OnReceivingData((TClient)client, e); + } + + Task ITcpPlugin.OnReceivingDataAsync(ITcpClientBase client, ByteBlockEventArgs e) + { + return OnReceivingDataAsync((TClient)client, e); + } + + void ITcpPlugin.OnSendingData(ITcpClientBase client, SendingEventArgs e) + { + OnSending((TClient)client, e); + } + + Task ITcpPlugin.OnSendingDataAsync(ITcpClientBase client, SendingEventArgs e) + { + return OnSendingDataAsync((TClient)client, e); + } + + #region 虚函数实现 + + /// + /// 成功建立连接 + /// + /// + /// + protected virtual void OnConnected(TClient client, TouchSocketEventArgs e) + { + } + + /// + /// 客户端连接成功后触发 + /// + /// + /// + /// + protected virtual Task OnConnectedAsync(TClient client, TouchSocketEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在请求连接时 + /// + /// + /// + protected virtual void OnConnecting(TClient client, OperationEventArgs e) + { + } + + /// + /// 在即将完成连接时触发。 + /// + /// + /// + /// + protected virtual Task OnConnectingAsync(TClient client, OperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在断开连接时 + /// + /// + /// + protected virtual void OnDisconnected(TClient client, DisconnectEventArgs e) + { + } + + /// + /// 会话断开后触发 + /// + /// + /// + /// + protected virtual Task OnDisconnectedAsync(TClient client, DisconnectEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + protected virtual void OnDisconnecting(TClient client, DisconnectEventArgs e) + { + } + + /// + protected virtual Task OnDisconnectingAsync(TClient client, DisconnectEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + protected virtual void OnIDChanged(TClient client, TouchSocketEventArgs e) + { + } + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + /// + protected virtual Task OnIDChangedAsync(TClient client, TouchSocketEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当载入配置时 + /// + /// + /// + protected virtual void OnLoadedConfig(object sender, ConfigEventArgs e) + { + } + + /// + /// 当完成配置载入时 + /// + /// + /// + /// + protected virtual Task OnLoadedConfigAsync(object sender, ConfigEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当完成配置载入时 + /// + /// + /// + protected virtual void OnLoadingConfig(object sender, ConfigEventArgs e) + { + } + + /// + /// 当载入配置时 + /// + /// + /// + /// + protected virtual Task OnLoadingConfigAsync(object sender, ConfigEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数,当设置e.Handled=true时,终止向下传递 + protected virtual void OnReceivedData(TClient client, ReceivedDataEventArgs e) + { + } + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + protected virtual Task OnReceivedDataAsync(TClient client, ReceivedDataEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// 客户端 + /// 参数 + protected virtual void OnReceivingData(TClient client, ByteBlockEventArgs e) + { + } + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// + /// + /// + protected virtual Task OnReceivingDataAsync(TClient client, ByteBlockEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// 客户端 + /// 参数,当设置e.IsPermitOperation=false时,中断发送。 + protected virtual void OnSending(TClient client, SendingEventArgs e) + { + } + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// + /// + /// + protected virtual Task OnSendingDataAsync(TClient client, SendingEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数实现 + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs.meta new file mode 100644 index 0000000..9eed6f3 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/TcpPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e17870b29c05feb4fa17c3e680d6bf85 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs new file mode 100644 index 0000000..bb9ee13 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UdpSessionPluginBase + /// + public class UdpSessionPluginBase : UdpSessionPluginBase + { + } + + /// + /// Udp插件实现类 + /// + public class UdpSessionPluginBase : DisposableObject, IUdpSessionPlugin + { + /// + /// + /// + public ILog Logger { get; set; } + + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + public IPluginsManager PluginsManager { get; set; } + + /// + /// + /// + /// + /// + void IUdpSessionPlugin.OnReceivedData(IUdpSession client, UdpReceivedDataEventArgs e) + { + OnReceivedData((TSession)client, e); + } + + Task IUdpSessionPlugin.OnReceivedDataAsync(IUdpSession client, UdpReceivedDataEventArgs e) + { + return OnReceivedDataAsync((TSession)client, e); + } + + /// + /// 收到数据 + /// + /// + /// + protected virtual void OnReceivedData(TSession client, UdpReceivedDataEventArgs e) + { + } + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + protected virtual Task OnReceivedDataAsync(TSession client, UdpReceivedDataEventArgs e) + { + return EasyTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs.meta new file mode 100644 index 0000000..b4ae9e4 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24b975108d7ba5240ac466de0cc14476 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient.meta new file mode 100644 index 0000000..f9680aa --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d076672d26b992849b2ba3bc0b211188 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs new file mode 100644 index 0000000..5463886 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 等待型客户端。 + /// + public interface IWaitingClient : IWaitSender,IDisposable where TClient : IClient, IDefaultSender, ISender + { + /// + /// 等待设置。 + /// + public WaitingOptions WaitingOptions { get;} + + /// + /// 客户端终端 + /// + TClient Client { get; } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs.meta new file mode 100644 index 0000000..1592f41 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5eb0e16f6518c1a49b3d06ca46a49489 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs new file mode 100644 index 0000000..4a9152a --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 响应数据。 + /// + public struct ResponsedData + { + private readonly byte[] m_data; + private readonly IRequestInfo m_requestInfo; + + /// + /// 构造函数 + /// + /// + /// + public ResponsedData(byte[] data, IRequestInfo requestInfo) + { + m_data = data; + m_requestInfo = requestInfo; + } + + /// + /// 数据 + /// + public byte[] Data => m_data; + + /// + /// RequestInfo + /// + public IRequestInfo RequestInfo => m_requestInfo; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs.meta new file mode 100644 index 0000000..cadb758 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/ResponsedData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71cb627545a35d5429d72479bf3f91ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs new file mode 100644 index 0000000..0595834 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs @@ -0,0 +1,382 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + internal class WaitingClient : DisposableObject, IWaitingClient where TClient : IClient, IDefaultSender, ISender + { + private readonly WaitData m_waitData; + + private volatile bool breaked; + + public WaitingClient(TClient client, WaitingOptions waitingOptions) + { + Client = client ?? throw new ArgumentNullException(nameof(client)); + m_waitData = new WaitData(); + WaitingOptions = waitingOptions; + } + + public bool CanSend + { + get + { + if (Client is ITcpClientBase tcpClient) + { + return tcpClient.Online; + } + else if (Client is IUdpSession) + { + return true; + } + else + { + return false; + } + } + } + + public TClient Client { get; private set; } + + public WaitingOptions WaitingOptions { get; set; } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + lock (this) + { + try + { + breaked = false; + m_waitData.Reset(); + if (WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) + { + tcpClient.Disconnected += this.OnDisconnected; + } + + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) + { + Client.OnHandleReceivedData += OnHandleReceivedData; + } + else + { + Client.OnHandleRawBuffer += OnHandleRawBuffer; + } + + if (WaitingOptions.RemoteIPHost != null && Client is IUdpSession session) + { + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) + { + session.Send(WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); + } + else + { + session.DefaultSend(WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); + } + } + else + { + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) + { + Client.Send(buffer, offset, length); + } + else + { + Client.DefaultSend(buffer, offset, length); + } + } + + m_waitData.SetCancellationToken(token); + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(); + case WaitDataStatus.Canceled: + { + if (this.WaitingOptions.ThrowBreakException && this.breaked) + { + throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。"); + } + return default; + } + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) + { + tcpClient.Disconnected -= this.OnDisconnected; + } + + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) + { + Client.OnHandleReceivedData -= OnHandleReceivedData; + } + else + { + Client.OnHandleRawBuffer -= OnHandleRawBuffer; + } + } + } + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(buffer, 0, buffer.Length, timeout, token); + } + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, token); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(buffer, offset, length, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(buffer, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(byteBlock, timeout, token); + }); + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(buffer, offset, length, timeout, token).Data; + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenReturn(buffer, 0, buffer.Length, timeout, token); + } + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, token); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(buffer, offset, length, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(buffer, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(byteBlock, timeout, token); + }); + } + + protected override void Dispose(bool disposing) + { + this.Client = default; + this.m_waitData.SafeDispose(); + base.Dispose(disposing); + } + + private void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + breaked = true; + this.m_waitData.Cancel(); + } + + private bool OnHandleRawBuffer(ByteBlock byteBlock) + { + ResponsedData responsedData = new ResponsedData(byteBlock.ToArray(), null); + return !m_waitData.Set(responsedData); + } + + /// + /// + /// + /// + /// + private bool OnHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + ResponsedData responsedData; + if (byteBlock != null) + { + responsedData = new ResponsedData(byteBlock.ToArray(), requestInfo); + } + else + { + responsedData = new ResponsedData(null, requestInfo); + } + return !m_waitData.Set(responsedData); + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs.meta new file mode 100644 index 0000000..83a4293 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 738f714818c616447946b96b93c98c8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs new file mode 100644 index 0000000..744dd32 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// WaitingClientExtensions + /// + public static class WaitingClientExtension + { + /// + /// 获取可等待的客户端。 + /// + /// + /// + /// + /// + public static IWaitingClient GetWaitingClient(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, IDefaultSender, ISender + { + WaitingClient waitingClient = new WaitingClient(client, waitingOptions); + return waitingClient; + } + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs.meta new file mode 100644 index 0000000..0bdb526 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14b9522d08ab7c2479a2a79603b4cc5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs new file mode 100644 index 0000000..5a817f0 --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 适配器筛选 + /// + public enum AdapterFilter + { + /// + /// 发送和接收都经过适配器 + /// + AllAdapter, + + /// + /// 发送经过适配器,接收不经过 + /// + SendAdapter, + + /// + /// 发送不经过适配器,接收经过 + /// + WaitAdapter, + + /// + /// 全都不经过适配器。 + /// + NoneAll + } + + /// + /// 等待设置 + /// + public class WaitingOptions + { + /// + /// 适配器筛选 + /// + public AdapterFilter AdapterFilter { get; set; } = AdapterFilter.AllAdapter; + /// + /// 当Client为Tcp系时。是否在断开连接时立即触发结果。默认会返回null。当时,会触发异常。 + /// + public bool BreakTrigger { get; set; } + + /// + /// 远程地址(仅在Udp模式下生效) + /// + public IPHost RemoteIPHost { get; set; } + + /// + /// 当Client为Tcp系时。是否在断开连接时以异常返回结果。 + /// + public bool ThrowBreakException { get; set; } = true; + } +} \ No newline at end of file diff --git a/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs.meta b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs.meta new file mode 100644 index 0000000..8d28b8d --- /dev/null +++ b/Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dca77e846b12acf40bb7edce6401af84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/Hand Driver Demo/UdexrealSample.unity b/Samples~/Hand Driver Demo/UdexrealSample.unity new file mode 100644 index 0000000..f84336e --- /dev/null +++ b/Samples~/Hand Driver Demo/UdexrealSample.unity @@ -0,0 +1,2561 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &178908012 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 178908015} + - component: {fileID: 178908014} + - component: {fileID: 178908013} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &178908013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &178908014 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &178908015 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178908012} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.12 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0.2588191, y: 0, z: 0, w: 0.9659258} + m_LocalPosition: {x: 0, y: 0.224, z: -0.1927} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 30, y: 0, z: 0} +--- !u!1 &1669286643 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1669286644} + - component: {fileID: 1669286645} + m_Layer: 0 + m_Name: Network + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1669286644 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1669286643} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1669286645 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1669286643} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d694a138ada737547be655b517ff143b, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 5555 +--- !u!4 &6322760157043851 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5932072128168019068} + m_LocalRotation: {x: 0.021973813, y: -0.037681088, z: -0.00082876993, w: 0.9990479} + m_LocalPosition: {x: 0.033171818, y: -0.00011021454, z: 0.0025033744} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 748470603218601360} + m_Father: {fileID: 2363757037305591233} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &214446489185135024 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8616749464320553597} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.00015978699, y: -0.0000319244, z: -0.00062570896} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4537819508369877214} + - {fileID: 8507005058661572490} + - {fileID: 5459949832865448039} + - {fileID: 2229113852275956350} + - {fileID: 860842083862283927} + m_Father: {fileID: 6394284460539294940} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &508315818274862559 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 556059018601076370} + m_Layer: 0 + m_Name: R_Pinky_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &556059018601076370 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 508315818274862559} + m_LocalRotation: {x: 0.000000022217463, y: -0.10944835, z: 0.0000000024463613, w: 0.9939925} + m_LocalPosition: {x: 0.06285565, y: 0.0000001417291, z: -0.00000027477583} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 925978096007585036} + m_Father: {fileID: 5459949832865448039} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &671979400434968908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4522263793486564093} + m_LocalRotation: {x: -0.00036969496, y: -0.004359701, z: -0.084519185, w: 0.9964123} + m_LocalPosition: {x: 0.07088554, y: -0.0000000031225003, z: -0.000000002885508} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2363757037305591233} + m_Father: {fileID: 8507005058661572490} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &675677663783772807 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160665490735513148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff3bfb33faef00d40880dd5952fd19e9, type: 3} + m_Name: + m_EditorClassIdentifier: + Network: {fileID: 0} + CharacterName: + Hand: 1 + Thumb1: {fileID: 860842083862283927} + Thumb2: {fileID: 8310384518608653617} + Thumb3: {fileID: 7303445391904380631} + Index1: {fileID: 5496311818784395322} + Index2: {fileID: 1112424348290694685} + Index3: {fileID: 4999533632160155606} + Middle1: {fileID: 671979400434968908} + Middle2: {fileID: 2363757037305591233} + Middle3: {fileID: 6322760157043851} + Ring1: {fileID: 3758562999754509161} + Ring2: {fileID: 3396408153264893052} + Ring3: {fileID: 3820432234125702229} + Pinky1: {fileID: 556059018601076370} + Pinky2: {fileID: 925978096007585036} + Pinky3: {fileID: 4925989245680324873} + Wrist: {fileID: 214446489185135024} + Pitch: 2 + Roll: 0 + Yaw: 1 + HasIMU: 0 + coefficient: 0.6 + Thumb1Offset: {x: 0, y: 0, z: 0} + NeedRealTransfrom: 1 + UsingNetwork: 1 + UsingAndroidService: 0 + thumb1: {x: 0, y: 0, z: 0} + thumb2: {x: 0, y: 0, z: 0} + thumb3: {x: 0, y: 0, z: 0} + index1: {x: 0, y: 0, z: 0} + index2: {x: 0, y: 0, z: 0} + index3: {x: 0, y: 0, z: 0} + middle1: {x: 0, y: 0, z: 0} + middle2: {x: 0, y: 0, z: 0} + middle3: {x: 0, y: 0, z: 0} + ring1: {x: 0, y: 0, z: 0} + ring2: {x: 0, y: 0, z: 0} + ring3: {x: 0, y: 0, z: 0} + pinky1: {x: 0, y: 0, z: 0} + pinky2: {x: 0, y: 0, z: 0} + pinky3: {x: 0, y: 0, z: 0} + Joy_X: 0 + Joy_Y: 0 + Button_A: 0 + Button_B: 0 + Button_Joystick: 0 + Button_Menu: 0 + SendBackIP: + Duration1: 1 + Amplitude1: 4 + Duration2: 1 + Amplitude2: 4 +--- !u!4 &748470603218601360 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6502233864751575502} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.025892606, y: -0.000000073447595, z: 0.000000050336155} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6322760157043851} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &860842083862283927 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6172359427428232399} + m_LocalRotation: {x: -0.27638686, y: -0.77303576, z: 0.18202926, w: 0.54119444} + m_LocalPosition: {x: -0.017913787, y: 0.029178023, z: 0.025298309} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8310384518608653617} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &925079791689987278 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3396408153264893052} + m_Layer: 0 + m_Name: R_Ring_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &925978096007585036 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5676528384244021321} + m_LocalRotation: {x: -0.056468494, y: 0.022603612, z: -0.0054254225, w: 0.9981338} + m_LocalPosition: {x: 0.029873928, y: 0.000000044091582, z: -0.00000006424834} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4925989245680324873} + m_Father: {fileID: 556059018601076370} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1092894868255631846 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6643260513880387009} + m_Layer: 0 + m_Name: L_Thumb_0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1112424348290694685 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6623980709240243409} + m_LocalRotation: {x: 0.07859818, y: -0, z: -0, w: 0.9969064} + m_LocalPosition: {x: 0.043286275, y: 0.000000013968487, z: -0.000000010911709} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4999533632160155606} + m_Father: {fileID: 5496311818784395322} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1160665490735513148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6394284460539294940} + - component: {fileID: 675677663783772807} + m_Layer: 0 + m_Name: Hand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1179545435151648496 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7449938260141068636} + m_Layer: 0 + m_Name: L_Ring_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1483641636172510471 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4437782591943742735} + m_LocalRotation: {x: 0.07859818, y: 0.000000044112156, z: -0.0000000034778946, w: 0.9969064} + m_LocalPosition: {x: -0.043286555, y: -1.11022296e-17, z: -1.7763568e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6900825591207550507} + m_Father: {fileID: 7119035830311120303} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1516923936631502984 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4537819508369877214} + m_Layer: 0 + m_Name: finger_index_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1563334061762160884 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4364775665665897489} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff3bfb33faef00d40880dd5952fd19e9, type: 3} + m_Name: + m_EditorClassIdentifier: + Network: {fileID: 0} + CharacterName: + Hand: 0 + Thumb1: {fileID: 6643260513880387009} + Thumb2: {fileID: 4860356083035197191} + Thumb3: {fileID: 5635012544043017313} + Index1: {fileID: 7119035830311120303} + Index2: {fileID: 1483641636172510471} + Index3: {fileID: 6900825591207550507} + Middle1: {fileID: 5926497155746532566} + Middle2: {fileID: 6220949525431291807} + Middle3: {fileID: 8250436794041268563} + Ring1: {fileID: 7449938260141068636} + Ring2: {fileID: 3476454750331030500} + Ring3: {fileID: 5745576405633313402} + Pinky1: {fileID: 5923872426823328339} + Pinky2: {fileID: 3139369216477100124} + Pinky3: {fileID: 7188099592734048766} + Wrist: {fileID: 8464987222797490959} + Pitch: 2 + Roll: 0 + Yaw: 1 + HasIMU: 0 + coefficient: 0.6 + Thumb1Offset: {x: 0, y: 0, z: 0} + NeedRealTransfrom: 1 + UsingNetwork: 1 + UsingAndroidService: 0 + thumb1: {x: 0, y: 0, z: 0} + thumb2: {x: 0, y: 0, z: 0} + thumb3: {x: 0, y: 0, z: 0} + index1: {x: 0, y: 0, z: 0} + index2: {x: 0, y: 0, z: 0} + index3: {x: 0, y: 0, z: 0} + middle1: {x: 0, y: 0, z: 0} + middle2: {x: 0, y: 0, z: 0} + middle3: {x: 0, y: 0, z: 0} + ring1: {x: 0, y: 0, z: 0} + ring2: {x: 0, y: 0, z: 0} + ring3: {x: 0, y: 0, z: 0} + pinky1: {x: 0, y: 0, z: 0} + pinky2: {x: 0, y: 0, z: 0} + pinky3: {x: 0, y: 0, z: 0} + Joy_X: 0 + Joy_Y: 0 + Button_A: 0 + Button_B: 0 + Button_Joystick: 0 + Button_Menu: 0 + SendBackIP: + Duration1: 1 + Amplitude1: 4 + Duration2: 1 + Amplitude2: 4 +--- !u!1 &1674725905380849052 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2139789476852871069} + m_Layer: 0 + m_Name: finger_middle_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1779072659313887930 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5459949832865448039} + m_Layer: 0 + m_Name: finger_pinky_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1782205013996300363 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8133983289645034287} + m_LocalRotation: {x: 0.5501436, y: 0.49554786, z: -0.4298879, w: 0.5166923} + m_LocalPosition: {x: -0.00051342254, y: -0.0065451264, z: 0.01634766} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7449938260141068636} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1818453212030041328 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8464987222797490959} + m_Layer: 0 + m_Name: L_Wrist + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1960731104228096300 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4509120418126981120} + m_Layer: 0 + m_Name: finger_thumb_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2118207532678258419 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6220949525431291807} + m_Layer: 0 + m_Name: L_Middle_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2134795069316445640 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5635012544043017313} + m_Layer: 0 + m_Name: L_Thumb_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2139789476852871069 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1674725905380849052} + m_LocalRotation: {x: 6.929678e-16, y: -1.0408341e-17, z: 1.2490009e-16, w: 1} + m_LocalPosition: {x: -0.025892286, y: -1.2686682e-10, z: 1.2212453e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8250436794041268563} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &2229113852275956350 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8620878470580026006} + m_LocalRotation: {x: -0.5166923, y: -0.42988783, z: -0.49554786, w: 0.55014354} + m_LocalPosition: {x: 0.000513423, y: -0.0065451255, z: 0.016347708} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3758562999754509161} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2246016610202118684 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3139369216477100124} + m_Layer: 0 + m_Name: L_Pinky_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &2336373233828122417 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7188099592734048766} + m_Layer: 0 + m_Name: L_Pinky_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2363757037305591233 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8775219295573228795} + m_LocalRotation: {x: -0.02197379, y: 0.037680954, z: 0.00082878245, w: 0.9990479} + m_LocalPosition: {x: 0.043108307, y: 0.00000005420781, z: 0.000000008444194} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6322760157043851} + m_Father: {fileID: 671979400434968908} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2745479420465899924 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3820432234125702229} + m_Layer: 0 + m_Name: R_Ring_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!137 &3004210974051931016 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5078406064857293169} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 3 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d28ff85c01985904bb98e5bc03251ff7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + serializedVersion: 2 + m_Quality: 0 + m_UpdateWhenOffscreen: 0 + m_SkinnedMotionVectors: 1 + m_Mesh: {fileID: 7927821202470849677, guid: 0305e3a35dffee44ea72d74b0d43fada, type: 3} + m_Bones: + - {fileID: 8742907838159378579} + - {fileID: 8464987222797490959} + - {fileID: 7771250235619228355} + - {fileID: 7119035830311120303} + - {fileID: 1483641636172510471} + - {fileID: 6900825591207550507} + - {fileID: 3022463771160063853} + - {fileID: 8477920962704591765} + - {fileID: 5926497155746532566} + - {fileID: 6220949525431291807} + - {fileID: 8250436794041268563} + - {fileID: 2139789476852871069} + - {fileID: 3238773086400040756} + - {fileID: 5923872426823328339} + - {fileID: 3139369216477100124} + - {fileID: 7188099592734048766} + - {fileID: 7788326014204426005} + - {fileID: 1782205013996300363} + - {fileID: 7449938260141068636} + - {fileID: 3476454750331030500} + - {fileID: 5745576405633313402} + - {fileID: 4317057570492409822} + - {fileID: 6643260513880387009} + - {fileID: 4860356083035197191} + - {fileID: 5635012544043017313} + - {fileID: 4509120418126981120} + m_BlendShapeWeights: [] + m_RootBone: {fileID: 8742907838159378579} + m_AABB: + m_Center: {x: 0.009932702, y: 0.01853694, z: 0.0827613} + m_Extent: {x: 0.05911108, y: 0.08356892, z: 0.11045481} + m_DirtyAABB: 0 +--- !u!4 &3022463771160063853 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5453305861822447136} + m_LocalRotation: {x: -0.087871745, y: -0.02274727, z: 0.0020071317, w: 0.99587005} + m_LocalPosition: {x: -0.02279774, y: -0.00018246654, z: -0.0010259174} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6900825591207550507} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3138456007448757676 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6784752715258439899} + m_LocalRotation: {x: -0.087871745, y: -0.02274727, z: 0.0020071317, w: 0.99587005} + m_LocalPosition: {x: 0.022797322, y: 0.0001825119, z: 0.0010259576} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4999533632160155606} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3139369216477100124 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2246016610202118684} + m_LocalRotation: {x: -0.056468446, y: 0.022603612, z: -0.005425421, w: 0.9981338} + m_LocalPosition: {x: -0.02987433, y: -3.0362518e-10, z: 1.02140514e-16} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7188099592734048766} + m_Father: {fileID: 5923872426823328339} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3194403237188042529 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8507005058661572490} + m_Layer: 0 + m_Name: finger_middle_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3238773086400040756 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5356405478463241161} + m_LocalRotation: {x: 0.5057481, y: 0.6016364, z: -0.36057425, w: 0.50223374} + m_LocalPosition: {x: 0.0024781574, y: -0.018981375, z: 0.01521364} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5923872426823328339} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3380521005008719725 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3974759597271355457} + m_Layer: 0 + m_Name: finger_pinky_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3396408153264893052 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 925079791689987278} + m_LocalRotation: {x: -0.021056127, y: 0.040366974, z: 0.00085085473, w: 0.9989627} + m_LocalPosition: {x: 0.040331636, y: -0.000000052882314, z: 0.000000042945093} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3820432234125702229} + m_Father: {fileID: 3758562999754509161} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3404879038379191373 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4317057570492409822} + m_Layer: 0 + m_Name: finger_ring_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3476454750331030500 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8699629255588642349} + m_LocalRotation: {x: -0.021056127, y: 0.040366974, z: 0.00085085473, w: 0.9989627} + m_LocalPosition: {x: -0.040331233, y: 1.5543122e-17, z: 1.5543122e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5745576405633313402} + m_Father: {fileID: 7449938260141068636} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3758562999754509161 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4793669001851238087} + m_LocalRotation: {x: -0.0017315906, y: -0.05142107, z: -0.03361232, w: 0.99810976} + m_LocalPosition: {x: 0.06597489, y: 0.000000019857714, z: -0.000000027218801} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3396408153264893052} + m_Father: {fileID: 2229113852275956350} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &3820432234125702229 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2745479420465899924} + m_LocalRotation: {x: 0.021056125, y: -0.04036691, z: -0.0008508534, w: 0.9989627} + m_LocalPosition: {x: 0.028395722, y: -0.00009681354, z: 0.0022965616} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5249512097504350987} + m_Father: {fileID: 3396408153264893052} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &3823084560694368822 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7119035830311120303} + m_Layer: 0 + m_Name: L_Index_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &3823939030950422181 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5496311818784395322} + m_Layer: 0 + m_Name: R_Index_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &3930443889687988978 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8310384518608653617} + m_Layer: 0 + m_Name: R_Thumb_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3974759597271355457 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3380521005008719725} + m_LocalRotation: {x: 0.1958613, y: 0.05253276, z: 0.0105080465, w: 0.97916716} + m_LocalPosition: {x: 0.017914427, y: 0.00074151315, z: -0.0017793871} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4925989245680324873} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4317057570492409822 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3404879038379191373} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.022430142, y: -1.3368179e-10, z: 2.40085e-10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5745576405633313402} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4325783370303563264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4925989245680324873} + m_Layer: 0 + m_Name: R_Pinky_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4364775665665897489 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8742907838159378579} + - component: {fileID: 1563334061762160884} + m_Layer: 0 + m_Name: Hand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4437782591943742735 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1483641636172510471} + m_Layer: 0 + m_Name: L_Index_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4509120418126981120 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1960731104228096300} + m_LocalRotation: {x: 1.2490009e-16, y: -1.3866696e-32, z: -1.110223e-16, w: 1} + m_LocalPosition: {x: -0.030464003, y: -5.2252597e-10, z: -7.5495166e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5635012544043017313} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4522263793486564093 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 671979400434968908} + m_Layer: 0 + m_Name: R_Middle_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4537819508369877214 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516923936631502984} + m_LocalRotation: {x: -0.550753, y: -0.53957784, z: -0.3514343, w: 0.5310563} + m_LocalPosition: {x: -0.001557247, y: 0.021073224, z: 0.014787008} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5496311818784395322} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4763710838890118350 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8477920962704591765} + m_Layer: 0 + m_Name: finger_middle_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4793669001851238087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3758562999754509161} + m_Layer: 0 + m_Name: R_Ring_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &4858515839211149561 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5926497155746532566} + m_Layer: 0 + m_Name: L_Middle_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4860356083035197191 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6469635495150361924} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.04040613, y: -1.3322676e-17, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5635012544043017313} + m_Father: {fileID: 6643260513880387009} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4925989245680324873 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4325783370303563264} + m_LocalRotation: {x: -0.13968116, y: -0.07503679, z: -0.012569679, w: 0.98726934} + m_LocalPosition: {x: 0.017959304, y: 0.00014881363, z: 0.0008222517} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3974759597271355457} + m_Father: {fileID: 925978096007585036} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4938117471892091556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7026629995582796419} + - component: {fileID: 4986107754757140926} + m_Layer: 0 + m_Name: RightHand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4971920943665295888 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8110118852186649490} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.030463943, y: 0.00000016772235, z: 0.00000011913329} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7303445391904380631} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!54 &4986107754757140926 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4938117471892091556} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 3 +--- !u!4 &4999533632160155606 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8176732961496558883} + m_LocalRotation: {x: 0.009326217, y: 0.022519214, z: -0.0037888263, w: 0.9996957} + m_LocalPosition: {x: 0.02827551, y: -0.000000076228126, z: -0.00000002183206} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3138456007448757676} + m_Father: {fileID: 1112424348290694685} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5078406064857293169 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5879237088916054589} + - component: {fileID: 3004210974051931016} + m_Layer: 0 + m_Name: vr_glove_left_slim + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5249512097504350987 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6221956022301426475} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.022430038, y: 0.000000040019266, z: 0.00000003203466} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3820432234125702229} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5309327284228994370 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6900825591207550507} + m_Layer: 0 + m_Name: L_Index_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5333547042377003323 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8694312561512733603} + - component: {fileID: 7913584612207383781} + m_Layer: 0 + m_Name: LeftHand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5356405478463241161 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3238773086400040756} + m_Layer: 0 + m_Name: finger_pinky_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5453305861822447136 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3022463771160063853} + m_Layer: 0 + m_Name: finger_index_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5459949832865448039 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1779072659313887930} + m_LocalRotation: {x: -0.50223374, y: -0.36057425, z: -0.6016364, w: 0.5057481} + m_LocalPosition: {x: -0.002478157, y: -0.018981375, z: 0.015213609} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 556059018601076370} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5496311818784395322 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3823939030950422181} + m_LocalRotation: {x: 0.007817584, y: 0.115047336, z: -0.0673426, w: 0.9910439} + m_LocalPosition: {x: 0.07379747, y: -0.00000011036788, z: 0.00000007059579} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1112424348290694685} + m_Father: {fileID: 4537819508369877214} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5635012544043017313 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2134795069316445640} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.03251682, y: -4.019752e-10, z: 8.881784e-18} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4509120418126981120} + m_Father: {fileID: 4860356083035197191} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5676528384244021321 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 925978096007585036} + m_Layer: 0 + m_Name: R_Pinky_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5745576405633313402 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6487436691325200521} + m_LocalRotation: {x: 0.021056125, y: -0.04036691, z: -0.0008508534, w: 0.9989627} + m_LocalPosition: {x: -0.028395902, y: 0.00009685899, z: -0.0022966054} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4317057570492409822} + m_Father: {fileID: 3476454750331030500} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5859416599995716932 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7933615073907520859} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7026629995582796419} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5879237088916054589 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5078406064857293169} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8694312561512733603} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5923872426823328339 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6477523313648946209} + m_LocalRotation: {x: -0.000000024055227, y: -0.10944835, z: -0.0000000026487172, w: 0.9939925} + m_LocalPosition: {x: -0.06285559, y: -0.00000015646219, z: 0.00000032782555} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3139369216477100124} + m_Father: {fileID: 3238773086400040756} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &5926497155746532566 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4858515839211149561} + m_LocalRotation: {x: -0.00036969496, y: -0.004359701, z: -0.084519185, w: 0.9964123} + m_LocalPosition: {x: -0.07088554, y: 4.3298696e-17, z: 6.661338e-18} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6220949525431291807} + m_Father: {fileID: 8477920962704591765} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5932072128168019068 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6322760157043851} + m_Layer: 0 + m_Name: R_Middle_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6172359427428232399 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 860842083862283927} + m_Layer: 0 + m_Name: R_Thumb_0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6220949525431291807 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2118207532678258419} + m_LocalRotation: {x: -0.02197379, y: 0.037680954, z: 0.00082878245, w: 0.9990479} + m_LocalPosition: {x: -0.043108538, y: 2.6645352e-17, z: 2.6645352e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8250436794041268563} + m_Father: {fileID: 5926497155746532566} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6221956022301426475 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5249512097504350987} + m_Layer: 0 + m_Name: finger_ring_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6394284460539294940 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160665490735513148} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 214446489185135024} + m_Father: {fileID: 7026629995582796419} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6469635495150361924 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4860356083035197191} + m_Layer: 0 + m_Name: L_Thumb_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6477523313648946209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5923872426823328339} + m_Layer: 0 + m_Name: L_Pinky_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6487436691325200521 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5745576405633313402} + m_Layer: 0 + m_Name: L_Ring_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6502233864751575502 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 748470603218601360} + m_Layer: 0 + m_Name: finger_middle_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &6623980709240243409 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1112424348290694685} + m_Layer: 0 + m_Name: R_Index_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6643260513880387009 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1092894868255631846} + m_LocalRotation: {x: -0.54119444, y: 0.18202926, z: 0.77303576, w: -0.27638686} + m_LocalPosition: {x: 0.017913802, y: 0.029178036, z: 0.025298318} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4860356083035197191} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6784752715258439899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3138456007448757676} + m_Layer: 0 + m_Name: finger_index_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6900825591207550507 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5309327284228994370} + m_LocalRotation: {x: 0.009326217, y: 0.022519171, z: -0.003788819, w: 0.9996957} + m_LocalPosition: {x: -0.028275203, y: 9.366404e-11, z: -1.4861739e-11} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3022463771160063853} + m_Father: {fileID: 1483641636172510471} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7026629995582796419 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4938117471892091556} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6394284460539294940} + - {fileID: 5859416599995716932} + m_Father: {fileID: 7268218674378355239} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7119035830311120303 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3823084560694368822} + m_LocalRotation: {x: 0.007817584, y: 0.115047336, z: -0.0673426, w: 0.9910439} + m_LocalPosition: {x: -0.073797464, y: 0.00000011920929, z: -0.000000059604645} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1483641636172510471} + m_Father: {fileID: 7771250235619228355} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7188099592734048766 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2336373233828122417} + m_LocalRotation: {x: -0.13968116, y: -0.07503679, z: -0.012569679, w: 0.98726934} + m_LocalPosition: {x: -0.017959101, y: -0.00014882295, z: -0.0008222617} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7788326014204426005} + m_Father: {fileID: 3139369216477100124} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7268218674378355236 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7268218674378355239} + m_Layer: 0 + m_Name: Interactions Hands + m_TagString: Untagged + m_Icon: {fileID: 2800000, guid: 0b09374c5d8c3464e9f29b2e29f8982c, type: 3} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7268218674378355239 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7268218674378355236} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8694312561512733603} + - {fileID: 7026629995582796419} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7303445391904380631 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7978712306862893037} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.032516796, y: -0.00000005848133, z: -0.00000003636439} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4971920943665295888} + m_Father: {fileID: 8310384518608653617} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!137 &7384835040074131152 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7933615073907520859} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 3 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d28ff85c01985904bb98e5bc03251ff7, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + serializedVersion: 2 + m_Quality: 0 + m_UpdateWhenOffscreen: 0 + m_SkinnedMotionVectors: 1 + m_Mesh: {fileID: -7313324671967738410, guid: 0305e3a35dffee44ea72d74b0d43fada, type: 3} + m_Bones: + - {fileID: 214446489185135024} + - {fileID: 4537819508369877214} + - {fileID: 5496311818784395322} + - {fileID: 1112424348290694685} + - {fileID: 4999533632160155606} + - {fileID: 8507005058661572490} + - {fileID: 671979400434968908} + - {fileID: 2363757037305591233} + - {fileID: 6322760157043851} + - {fileID: 5459949832865448039} + - {fileID: 556059018601076370} + - {fileID: 925978096007585036} + - {fileID: 4925989245680324873} + - {fileID: 2229113852275956350} + - {fileID: 3758562999754509161} + - {fileID: 3396408153264893052} + - {fileID: 3820432234125702229} + - {fileID: 860842083862283927} + - {fileID: 8310384518608653617} + - {fileID: 7303445391904380631} + - {fileID: 4971920943665295888} + m_BlendShapeWeights: [] + m_RootBone: {fileID: 214446489185135024} + m_AABB: + m_Center: {x: -0.010092495, y: 0.018568892, z: 0.083387025} + m_Extent: {x: 0.059111074, y: 0.083568946, z: 0.11045482} + m_DirtyAABB: 0 +--- !u!4 &7449938260141068636 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179545435151648496} + m_LocalRotation: {x: -0.0017315906, y: -0.05142107, z: -0.03361232, w: 0.99810976} + m_LocalPosition: {x: -0.06597498, y: -0.0000000018626451, z: 1.0547119e-17} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3476454750331030500} + m_Father: {fileID: 1782205013996300363} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7771250235619228355 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8797527941768423211} + m_LocalRotation: {x: 0.5310563, y: 0.3514343, z: -0.53957784, w: 0.550753} + m_LocalPosition: {x: 0.001557245, y: 0.02107323, z: 0.014786973} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7119035830311120303} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &7788326014204426005 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117458629084437052} + m_LocalRotation: {x: 0.1958613, y: 0.05253276, z: 0.0105080465, w: 0.97916716} + m_LocalPosition: {x: -0.017914493, y: -0.00074155553, z: 0.0017794578} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7188099592734048766} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!54 &7913584612207383781 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5333547042377003323} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 3 +--- !u!1 &7933615073907520859 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5859416599995716932} + - component: {fileID: 7384835040074131152} + m_Layer: 0 + m_Name: vr_glove_right_slim + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &7978712306862893037 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7303445391904380631} + m_Layer: 0 + m_Name: R_Thumb_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8110118852186649490 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4971920943665295888} + m_Layer: 0 + m_Name: finger_thumb_r_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8133983289645034287 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1782205013996300363} + m_Layer: 0 + m_Name: finger_ring_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8176732961496558883 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4999533632160155606} + m_Layer: 0 + m_Name: R_Index_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8250436794041268563 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8316072831360955084} + m_LocalRotation: {x: 0.021973813, y: -0.037681088, z: -0.00082876993, w: 0.9990479} + m_LocalPosition: {x: -0.033171408, y: 0.00011017601, z: -0.002503392} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2139789476852871069} + m_Father: {fileID: 6220949525431291807} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8310384518608653617 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3930443889687988978} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.04040613, y: 0.000000032195924, z: 0.000000017957513} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7303445391904380631} + m_Father: {fileID: 860842083862283927} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8316072831360955084 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8250436794041268563} + m_Layer: 0 + m_Name: L_Middle_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8464987222797490959 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1818453212030041328} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.00015978744, y: -0.000031924377, z: -0.0006257091} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7771250235619228355} + - {fileID: 8477920962704591765} + - {fileID: 3238773086400040756} + - {fileID: 1782205013996300363} + - {fileID: 6643260513880387009} + m_Father: {fileID: 8742907838159378579} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8477920962704591765 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4763710838890118350} + m_LocalRotation: {x: 0.5617497, y: 0.41973728, z: -0.47298795, w: 0.5334232} + m_LocalPosition: {x: -0.0021773048, y: 0.0071195434, z: 0.016318835} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5926497155746532566} + m_Father: {fileID: 8464987222797490959} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &8507005058661572490 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3194403237188042529} + m_LocalRotation: {x: -0.5334232, y: -0.47298795, z: -0.41973728, w: 0.5617497} + m_LocalPosition: {x: 0.002177303, y: 0.007119544, z: 0.01631881} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 671979400434968908} + m_Father: {fileID: 214446489185135024} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8616749464320553597 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 214446489185135024} + m_Layer: 0 + m_Name: R_Wrist + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8620878470580026006 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2229113852275956350} + m_Layer: 0 + m_Name: finger_ring_meta_r + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8694312561512733603 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5333547042377003323} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8742907838159378579} + - {fileID: 5879237088916054589} + m_Father: {fileID: 7268218674378355239} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8699629255588642349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3476454750331030500} + m_Layer: 0 + m_Name: L_Ring_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8742907838159378579 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4364775665665897489} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8464987222797490959} + m_Father: {fileID: 8694312561512733603} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8775219295573228795 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2363757037305591233} + m_Layer: 0 + m_Name: R_Middle_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &8797527941768423211 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7771250235619228355} + m_Layer: 0 + m_Name: finger_index_meta_l + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &9117458629084437052 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7788326014204426005} + m_Layer: 0 + m_Name: finger_pinky_l_end + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 diff --git a/Samples~/Hand Driver Demo/UdexrealSample.unity.meta b/Samples~/Hand Driver Demo/UdexrealSample.unity.meta new file mode 100644 index 0000000..decc2b2 --- /dev/null +++ b/Samples~/Hand Driver Demo/UdexrealSample.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6582a4211ab8af14795b722caefc0aee +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: