├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── Uragano.sln ├── _config.yml ├── build.cake ├── build.ps1 ├── build.sh ├── cake.config ├── icon.png ├── samples ├── GenericHostSample │ ├── GenericHostSample.csproj │ ├── PersonService.cs │ ├── Program.cs │ └── uragano.json ├── Sample.Common │ ├── CircuitBreakerEvent.cs │ ├── ClientClassInterceptorAttribute.cs │ ├── ClientGlobalInterceptor.cs │ ├── ClientMethodInterceptorAttribute.cs │ ├── ResponseResult.cs │ ├── ResultModel.cs │ ├── Sample.Common.csproj │ ├── ServerClassInterceptorAttribute.cs │ ├── ServerGlobalInterceptor.cs │ ├── ServerInterceptorAttribute.cs │ └── ServerMethodInterceptorAttribute.cs ├── Sample.Server │ ├── Controllers │ │ └── ValuesController.cs │ ├── HelloService.cs │ ├── Program.cs │ ├── Sample.Server.csproj │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── log4net.config │ └── nlog.config ├── Sample.Service.Interfaces │ ├── ClientGlobal_2_Interceptor.cs │ ├── ClientInterceptor_1_Attribute.cs │ ├── ClientInterceptor_2_Attribute.cs │ ├── ClientMethodInterceptor_1_Attribute.cs │ ├── ClientMethodInterceptor_2_Attribute.cs │ ├── IHelloService.cs │ ├── IPersonService.cs │ ├── Sample.Service.Interfaces.csproj │ └── ServerGlobalInterceptor.cs └── Sample.WebApi │ ├── Controllers │ └── ValuesController.cs │ ├── MyInterceptor1Attribute.cs │ ├── MyInterceptor2Attribute.cs │ ├── MyInterceptor3Attribute.cs │ ├── MyInterceptor4Attribute.cs │ ├── Program.cs │ ├── Sample.WebApi.csproj │ ├── Startup.cs │ ├── Test1Interceptor.cs │ ├── Test2INterceptor.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── src ├── Uragano.Abstract │ ├── AsyncLock.cs │ ├── CachingAttribute.cs │ ├── CircuitBreaker │ │ ├── CircuitBreakerOptions.cs │ │ ├── ICircuitBreaker.cs │ │ ├── ICircuitBreakerEvent.cs │ │ ├── IScriptInjection.cs │ │ ├── ScriptDescriptor.cs │ │ └── ServiceCIrcuitBreakerOptions.cs │ ├── CircuitBreakerAttribute.cs │ ├── ConsistentHash │ │ ├── ConsistentHash.cs │ │ └── IConsistentHash.cs │ ├── EnvironmentVariableReader.cs │ ├── EnvironmentVariables.cs │ ├── Exceptions │ │ ├── DuplicateRouteException.cs │ │ ├── NotFoundNodeException.cs │ │ ├── NotFoundRouteException.cs │ │ └── RemoteInvokeException.cs │ ├── ICaching.cs │ ├── ICachingKeyGenerator.Default.cs │ ├── ICachingKeyGenerator.cs │ ├── ICachingOptions.cs │ ├── ICodec.cs │ ├── IInterceptor.cs │ ├── IInterceptorContext.cs │ ├── IInvokeMessage.cs │ ├── ILoadBalancing.cs │ ├── IPHelper.cs │ ├── IRemotingInvoke.cs │ ├── IService.cs │ ├── IServiceResult.cs │ ├── ITransportMessage.cs │ ├── IUraganoBuilder.cs │ ├── InvokeMessage.cs │ ├── NonCachingAttribute.cs │ ├── NonCircuitBreakerAttribute.cs │ ├── NonInterceptAttribute.cs │ ├── Service │ │ ├── IMethodInvoker.cs │ │ └── IServiceFactory.cs │ ├── ServiceDescriptor.cs │ ├── ServiceDiscovery │ │ ├── IServiceDiscovery.cs │ │ ├── IServiceDiscoveryClientConfiguration.cs │ │ ├── IServiceRegisterConfiguration.cs │ │ └── ServiceDiscoveryInfo.cs │ ├── ServiceDiscoveryNameAttribute.cs │ ├── ServiceResult.cs │ ├── ServiceRouteAttribute.cs │ ├── TransportMessage.cs │ ├── Uragano.Abstractions.csproj │ ├── UraganoOptions.cs │ └── UraganoSettings.cs ├── Uragano.Caching.Memory │ ├── MemoryCaching.cs │ ├── MemoryCachingOptions.cs │ ├── MemoryCachingValue.cs │ ├── Uragano.Caching.Memory.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Caching.Redis │ ├── RedisCaching.cs │ ├── RedisOptions.cs │ ├── RedisPartitionCaching.cs │ ├── Uragano.Caching.Redis.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Codec.MessagePack │ ├── MessagePackCodec.cs │ ├── SerializerHelper.cs │ └── Uragano.Codec.MessagePack.csproj ├── Uragano.Consul │ ├── CommonMethods.cs │ ├── ConsulClientConfigure.cs │ ├── ConsulRegisterServiceConfiguration.cs │ ├── ConsulServiceDiscovery.cs │ ├── ServiceStatusManageService.cs │ ├── Uragano.Consul.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Core │ ├── HostedService │ │ ├── BootstrapStartup.cs │ │ ├── InfrastructureStartup.cs │ │ ├── RemotingClientStartup.cs │ │ └── ServiceDiscoveryStartup.cs │ ├── PollyCircuitBreaker.cs │ ├── ScriptInjection.cs │ ├── ServiceCollectionExtensions.cs │ ├── ServiceExtensions.cs │ ├── Uragano.Core.csproj │ └── UraganoBuilder.cs ├── Uragano.DynamicProxy │ ├── DynamicProxyAbstract.cs │ ├── Interceptor │ │ ├── CachingDefaultInterceptor.cs │ │ ├── ClientDefaultInterceptor.cs │ │ ├── InterceptorAbstract.cs │ │ ├── InterceptorAttributeAbstract.cs │ │ ├── InterceptorContext.cs │ │ └── ServerDefaultInterceptor.cs │ ├── MethodInvoker.cs │ ├── ProxyGenerator.cs │ ├── ReflectHelper.cs │ ├── RemotingInvoke.cs │ ├── ServiceBuilder.cs │ ├── ServiceFactory.cs │ └── Uragano.DynamicProxy.csproj ├── Uragano.Logging.Exceptionless │ ├── Uragano.Logging.Exceptionless.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Logging.Log4net │ ├── Log4NetLogger.cs │ ├── Log4NetProvider.cs │ ├── Uragano.Logging.Log4Net.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Logging.NLog │ ├── Uragano.Logging.NLog.csproj │ └── UraganoBuilderExtensions.cs ├── Uragano.Remoting │ ├── IBootstrap.cs │ ├── IClient.Default.cs │ ├── IClient.cs │ ├── IClientFactory.Default.cs │ ├── IClientFactory.cs │ ├── IMessageListener.Default.cs │ ├── IMessageListener.cs │ ├── LoadBalancing │ │ ├── LoadBalancing.ConsistentHash.cs │ │ ├── LoadBalancing.Polling.cs │ │ ├── LoadBalancing.Random.cs │ │ ├── LoadBalancing.WeightedPolling.cs │ │ ├── LoadBalancing.WeightedRandom.cs │ │ └── LoadBalancing.cs │ ├── MessageDecoder.cs │ ├── MessageEncoder.cs │ ├── ServerBootstrap.cs │ ├── ServerMessageHandler.cs │ ├── TransportContext.cs │ └── Uragano.Remoting.csproj └── Uragano.ZooKeeper │ ├── CommonMethods.cs │ ├── Uragano.ZooKeeper.csproj │ ├── UraganoBuilderExtensions.cs │ ├── UraganoWatcher.cs │ ├── ZooKeeperClientConfigure.cs │ ├── ZooKeeperRegisterServiceConfiguration.cs │ └── ZooKeeperServiceDiscovery.cs └── test └── XUnitTest ├── CodecMessagePackTest.cs ├── ConsulTest.cs ├── DynamicProxy └── MethodInvokerTest.cs └── XUnitTest.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kakous 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Uragano 2 | A simple, high performance RPC library. 3 | 4 | Support load balancing, circuit breaker, fallback, caching, intercepting. 5 | 6 | ## Package & Status 7 | Package | NuGet 8 | --------|------ 9 | Uragano.Abstractions|[![NuGet package](https://buildstats.info/nuget/Uragano.Abstractions?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Abstractions) 10 | Uragano.Codec.MessagePack|[![NuGet package](https://buildstats.info/nuget/Uragano.Codec.MessagePack?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Codec.MessagePack) 11 | Uragano.Consul|[![NuGet package](https://buildstats.info/nuget/Uragano.Consul?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Consul) 12 | Uragano.ZooKeeper|[![NuGet package](https://buildstats.info/nuget/Uragano.ZooKeeper?includePreReleases=true)](https://www.nuget.org/packages/Uragano.ZooKeeper) 13 | Uragano.DynamicProxy|[![NuGet package](https://buildstats.info/nuget/Uragano.DynamicProxy?includePreReleases=true)](https://www.nuget.org/packages/Uragano.DynamicProxy) 14 | Uragano.Remoting|[![NuGet package](https://buildstats.info/nuget/Uragano.Remoting?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Remoting) 15 | Uragano.Core|[![NuGet package](https://buildstats.info/nuget/Uragano.Core?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Core) 16 | Uragano.Caching.Memory|[![NuGet package](https://buildstats.info/nuget/Uragano.Caching.Memory?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Caching.Memory) 17 | Uragano.Caching.Redis|[![NuGet package](https://buildstats.info/nuget/Uragano.Caching.Redis?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Caching.Redis) 18 | Uragano.Logging.Exceptionless|[![NuGet package](https://buildstats.info/nuget/Uragano.Logging.Exceptionless?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Logging.Exceptionless) 19 | Uragano.Logging.Log4Net|[![NuGet package](https://buildstats.info/nuget/Uragano.Caching.Redis?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Logging.Log4Net) 20 | Uragano.Logging.NLog|[![NuGet package](https://buildstats.info/nuget/Uragano.Logging.NLog?includePreReleases=true)](https://www.nuget.org/packages/Uragano.Logging.NLog) 21 | 22 | ## Performance 23 | ### Computer configuration 24 | 25 | Item|Information 26 | :---------:|---------- 27 | CPU|i5-4590 @ 3.30GHZ 3.30 GHZ 28 | RAM|16GB 29 | OS|Windows 10 x64 30 | 31 | ### Test results using Jmeter 32 | Samples|Average|Median|90% Line|95% Line|99% Line|Min|Max|Error %|Throughput|KB/sec 33 | :-------:|:--------:|:------:|:-------:|:--------:|:--------:|:----:|:---:|:------:|:----------:|:------: 34 | 250000|54|53|71|73|81|1|120|0.00%|8943.6/sec|1825.4 35 | 36 | 37 | ## Use example 38 | Use the example to refer to another [simple micro-services shop](https://github.com/1100100/MicroServicesShop), using docker orchestration services. 39 | 40 | ## Docs 41 | See [wiki documentation](https://github.com/ww198643/Uragano/wiki). 42 | 43 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /build.cake: -------------------------------------------------------------------------------- 1 | #addin Cake.Git 2 | 3 | /////////////////////////////////////////////////////////////////////////////// 4 | // ARGUMENTS 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | var output=Argument("output", "Output"); 8 | var version=Argument("version", "0.0.4"); 9 | var target = Argument("target", "Default"); 10 | var release = Argument("release", true); 11 | var nugetApiKey = Argument("nugetApiKey", null); 12 | var currentBranch = Argument("currentBranch", GitBranchCurrent("./").FriendlyName); 13 | var configuration=release?"Release":"Debug"; 14 | 15 | /////////////////////////////////////////////////////////////////////////////// 16 | // SETUP / TEARDOWN 17 | /////////////////////////////////////////////////////////////////////////////// 18 | 19 | Setup(ctx => 20 | { 21 | // Executed BEFORE the first task. 22 | Information("Running tasks..."); 23 | }); 24 | 25 | Teardown(ctx => 26 | { 27 | // Executed AFTER the last task. 28 | Information("Finished running tasks."); 29 | }); 30 | 31 | /////////////////////////////////////////////////////////////////////////////// 32 | // TASKS 33 | /////////////////////////////////////////////////////////////////////////////// 34 | 35 | Task("UpdateVersion").DoesForEach(GetFiles("**/Uragano.*.csproj"),(file)=>{ 36 | XmlPoke(file,"/Project/PropertyGroup/Version",version); 37 | XmlPoke(file,"/Project/PropertyGroup/GeneratePackageOnBuild","false"); 38 | XmlPoke(file,"/Project/PropertyGroup/Description","A simple, high performance RPC library."); 39 | XmlPoke(file,"/Project/PropertyGroup/PackageProjectUrl","https://github.com/1100100/Uragano"); 40 | XmlPoke(file,"/Project/PropertyGroup/PackageTags","Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection"); 41 | XmlPoke(file,"/Project/PropertyGroup/PackageIconUrl","https://raw.githubusercontent.com/1100100/Uragano/master/icon.png"); 42 | XmlPoke(file,"/Project/PropertyGroup/Authors","Owen"); 43 | XmlPoke(file,"/Project/PropertyGroup/PackageLicenseExpression","MIT"); 44 | }); 45 | 46 | Task("Restore").Does(()=>{ 47 | DotNetCoreRestore(); 48 | }); 49 | 50 | Task("Build").Does(()=>{ 51 | DotNetCoreBuild("Uragano.sln",new DotNetCoreBuildSettings{ 52 | Configuration=configuration 53 | }); 54 | }); 55 | 56 | Task("CleanPackage").Does(()=>{ 57 | if(DirectoryExists(output)) 58 | { 59 | DeleteDirectory(output,true); 60 | } 61 | }); 62 | 63 | Task("Pack") 64 | .IsDependentOn("CleanPackage") 65 | .IsDependentOn("UpdateVersion") 66 | .DoesForEach(GetFiles("**/Uragano.*.csproj"),(file)=>{ 67 | DotNetCorePack(file.ToString(),new DotNetCorePackSettings{ 68 | OutputDirectory=output, 69 | Configuration=configuration 70 | }); 71 | }); 72 | 73 | Task("Push") 74 | .IsDependentOn("Pack") 75 | .Does(()=>{ 76 | var nuGetPushSettings= new NuGetPushSettings { 77 | Source="https://www.nuget.org/api/v2/package", 78 | ApiKey=nugetApiKey 79 | }; 80 | if(currentBranch=="master") 81 | { 82 | foreach (var package in GetFiles("Output/*.nupkg")) 83 | { 84 | NuGetPush(package,nuGetPushSettings); 85 | } 86 | } 87 | else 88 | { 89 | Information("Non-master build. Not publishing to NuGet. Current branch: " + currentBranch); 90 | } 91 | }); 92 | 93 | Task("Default") 94 | .IsDependentOn("Restore") 95 | .IsDependentOn("Build") 96 | .Does(() => { 97 | 98 | }); 99 | 100 | 101 | 102 | RunTarget(target); -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ########################################################################## 4 | # This is the Cake bootstrapper script for Linux and OS X. 5 | # This file was downloaded from https://github.com/cake-build/resources 6 | # Feel free to change this file to fit your needs. 7 | ########################################################################## 8 | 9 | # Define directories. 10 | SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 11 | TOOLS_DIR=$SCRIPT_DIR/tools 12 | ADDINS_DIR=$TOOLS_DIR/Addins 13 | MODULES_DIR=$TOOLS_DIR/Modules 14 | NUGET_EXE=$TOOLS_DIR/nuget.exe 15 | CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe 16 | PACKAGES_CONFIG=$TOOLS_DIR/packages.config 17 | PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum 18 | ADDINS_PACKAGES_CONFIG=$ADDINS_DIR/packages.config 19 | MODULES_PACKAGES_CONFIG=$MODULES_DIR/packages.config 20 | 21 | # Define md5sum or md5 depending on Linux/OSX 22 | MD5_EXE= 23 | if [[ "$(uname -s)" == "Darwin" ]]; then 24 | MD5_EXE="md5 -r" 25 | else 26 | MD5_EXE="md5sum" 27 | fi 28 | 29 | # Define default arguments. 30 | SCRIPT="build.cake" 31 | CAKE_ARGUMENTS=() 32 | 33 | # Parse arguments. 34 | for i in "$@"; do 35 | case $1 in 36 | -s|--script) SCRIPT="$2"; shift ;; 37 | --) shift; CAKE_ARGUMENTS+=("$@"); break ;; 38 | *) CAKE_ARGUMENTS+=("$1") ;; 39 | esac 40 | shift 41 | done 42 | 43 | # Make sure the tools folder exist. 44 | if [ ! -d "$TOOLS_DIR" ]; then 45 | mkdir "$TOOLS_DIR" 46 | fi 47 | 48 | # Make sure that packages.config exist. 49 | if [ ! -f "$TOOLS_DIR/packages.config" ]; then 50 | echo "Downloading packages.config..." 51 | curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages 52 | if [ $? -ne 0 ]; then 53 | echo "An error occurred while downloading packages.config." 54 | exit 1 55 | fi 56 | fi 57 | 58 | # Download NuGet if it does not exist. 59 | if [ ! -f "$NUGET_EXE" ]; then 60 | echo "Downloading NuGet..." 61 | curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe 62 | if [ $? -ne 0 ]; then 63 | echo "An error occurred while downloading nuget.exe." 64 | exit 1 65 | fi 66 | fi 67 | 68 | # Restore tools from NuGet. 69 | pushd "$TOOLS_DIR" >/dev/null 70 | if [ ! -f "$PACKAGES_CONFIG_MD5" ] || [ "$( cat "$PACKAGES_CONFIG_MD5" | sed 's/\r$//' )" != "$( $MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' )" ]; then 71 | find . -type d ! -name . ! -name 'Cake.Bakery' | xargs rm -rf 72 | fi 73 | 74 | mono "$NUGET_EXE" install -ExcludeVersion 75 | if [ $? -ne 0 ]; then 76 | echo "Could not restore NuGet tools." 77 | exit 1 78 | fi 79 | 80 | $MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' >| "$PACKAGES_CONFIG_MD5" 81 | 82 | popd >/dev/null 83 | 84 | # Restore addins from NuGet. 85 | if [ -f "$ADDINS_PACKAGES_CONFIG" ]; then 86 | pushd "$ADDINS_DIR" >/dev/null 87 | 88 | mono "$NUGET_EXE" install -ExcludeVersion 89 | if [ $? -ne 0 ]; then 90 | echo "Could not restore NuGet addins." 91 | exit 1 92 | fi 93 | 94 | popd >/dev/null 95 | fi 96 | 97 | # Restore modules from NuGet. 98 | if [ -f "$MODULES_PACKAGES_CONFIG" ]; then 99 | pushd "$MODULES_DIR" >/dev/null 100 | 101 | mono "$NUGET_EXE" install -ExcludeVersion 102 | if [ $? -ne 0 ]; then 103 | echo "Could not restore NuGet modules." 104 | exit 1 105 | fi 106 | 107 | popd >/dev/null 108 | fi 109 | 110 | # Make sure that Cake has been installed. 111 | if [ ! -f "$CAKE_EXE" ]; then 112 | echo "Could not find Cake.exe at '$CAKE_EXE'." 113 | exit 1 114 | fi 115 | 116 | # Start Cake 117 | exec mono "$CAKE_EXE" $SCRIPT "${CAKE_ARGUMENTS[@]}" 118 | -------------------------------------------------------------------------------- /cake.config: -------------------------------------------------------------------------------- 1 | ; This is the default configuration file for Cake. 2 | ; This file was downloaded from https://github.com/cake-build/resources 3 | 4 | [Nuget] 5 | Source=https://api.nuget.org/v3/index.json 6 | UseInProcessClient=true 7 | LoadDependencies=false 8 | 9 | [Paths] 10 | Tools=./tools 11 | Addins=./tools/Addins 12 | Modules=./tools/Modules 13 | 14 | [Settings] 15 | SkipVerification=false 16 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeeLyn/Uragano/f204c298df927319dae48fc4b8db42037cac8e44/icon.png -------------------------------------------------------------------------------- /samples/GenericHostSample/GenericHostSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | PreserveNewest 16 | Always 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.logging.debug\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Debug.dll 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /samples/GenericHostSample/PersonService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Sample.Service.Interfaces; 6 | 7 | namespace GenericHostSample 8 | { 9 | 10 | public class PersonService : IPersonService 11 | { 12 | private IHelloService HelloService { get; } 13 | 14 | public PersonService(IHelloService helloService) 15 | { 16 | HelloService = helloService; 17 | } 18 | 19 | public async Task GetName(int id) 20 | { 21 | await Task.Delay(TimeSpan.FromHours(1)); 22 | return await Task.FromResult(new 23 | { 24 | name = $"[{id}]Owen", 25 | //message = await HelloService.SayHello("Owen") 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/GenericHostSample/uragano.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace", 5 | "System": "Warning", 6 | "Microsoft": "Warning" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "Uragano": { 11 | "Server": { 12 | "address": "192.168.1.129", 13 | "port": 5002, 14 | "certUrl": "", 15 | "certPwd": "", 16 | "weight": 1 17 | }, 18 | "ServiceDiscovery": { 19 | "Consul": { 20 | "Client": { 21 | "Address": "http://192.168.1.254:8500", 22 | "Token": "5ece74af-19d1-0e61-b25c-b9665d29f50b" 23 | }, 24 | "Service": { 25 | "Id": null, 26 | "Name": "PersionService", 27 | "tags": null, 28 | "EnableTagOverride": false, 29 | "meta": null, 30 | "HealthCheckInterval": 10 31 | } 32 | }, 33 | "ZooKeeper": { 34 | "Client": { 35 | "ConnectionString": "localhost:2181" 36 | }, 37 | "Service": { 38 | "Name": "PersionService", 39 | "Id": null 40 | } 41 | } 42 | }, 43 | "Caching": { 44 | "Redis": { 45 | "KeyPrefix": "Uragano", 46 | "ExpireSeconds": 60, 47 | "KeyGenerator": null, 48 | "ConnectionStrings": [ 49 | { 50 | "Host": "192.168.1.254", 51 | "Port": 6379, 52 | "Password": "nihao123", 53 | "DefaultDatabase": 13, 54 | "PoolSize": 50, 55 | "SSL": false, 56 | "ConnectionTimeout": -1, 57 | "PreHeat": true, 58 | "WriteBuffer": 10240, 59 | "TryIt": 0, 60 | "Name": "" 61 | } 62 | ] 63 | }, 64 | "Memory": { 65 | "ExpireSeconds": 60 66 | } 67 | }, 68 | "Logging": { 69 | "Exceptionless": { 70 | "apiKey": "avtkum3kDogGmLjMCQim9wgC8zHDbcrzQEpDNNJ7" 71 | } 72 | }, 73 | "Options": { 74 | "ThreadPool_MinThreads": 100, 75 | "DotNetty_Event_Loop_Count": 100 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /samples/Sample.Common/CircuitBreakerEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Logging; 5 | using Uragano.Abstractions.CircuitBreaker; 6 | 7 | namespace Sample.Common 8 | { 9 | public class CircuitBreakerEvent : ICircuitBreakerEvent 10 | { 11 | private ILogger Logger { get; } 12 | 13 | public CircuitBreakerEvent(ILogger logger) 14 | { 15 | Logger = logger; 16 | } 17 | public async Task OnFallback(string route, MethodInfo methodInfo) 18 | { 19 | Logger.LogWarning("Raise OnFallback"); 20 | await Task.CompletedTask; 21 | } 22 | 23 | public async Task OnBreak(string route, MethodInfo methodInfo, Exception exception, TimeSpan time) 24 | { 25 | Logger.LogError($"Raise OnBreak;{exception.Message}"); 26 | await Task.CompletedTask; 27 | } 28 | 29 | public async Task OnRest(string route, MethodInfo methodInfo) 30 | { 31 | Logger.LogWarning("Raise OnRest"); 32 | await Task.CompletedTask; 33 | } 34 | 35 | public async Task OnHalfOpen(string route, MethodInfo methodInfo) 36 | { 37 | Logger.LogWarning("Raise OnHalfOpen"); 38 | await Task.CompletedTask; 39 | } 40 | 41 | public async Task OnTimeOut(string route, MethodInfo methodInfo, Exception exception) 42 | { 43 | Logger.LogWarning($"Raise OnTimeOut;{exception.Message}"); 44 | await Task.CompletedTask; 45 | } 46 | 47 | public async Task OnRetry(string route, MethodInfo methodInfo, Exception exception, int retryTimes) 48 | { 49 | Logger.LogWarning($"Raise OnRetry;{exception.Message};{retryTimes}"); 50 | await Task.CompletedTask; 51 | } 52 | 53 | public async Task OnBulkheadRejected(string route, MethodInfo methodInfo) 54 | { 55 | Logger.LogWarning("Raise OnBulkheadRejected;"); 56 | await Task.CompletedTask; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /samples/Sample.Common/ClientClassInterceptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ClientClassInterceptorAttribute : InterceptorAttributeAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ClientClassInterceptorAttribute(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | public ClientClassInterceptorAttribute() 18 | { 19 | } 20 | 21 | public override async Task Intercept(IInterceptorContext context) 22 | { 23 | Logger.LogTrace("\n------------------>Client class interceptor attribute\n"); 24 | var r = await context.Next(); 25 | return r; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/Sample.Common/ClientGlobalInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ClientGlobalInterceptor : InterceptorAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ClientGlobalInterceptor(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | 18 | public override async Task Intercept(IInterceptorContext context) 19 | { 20 | 21 | Logger.LogTrace("\n---------------->Client global interceptor\n"); 22 | return await context.Next(); 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/Sample.Common/ClientMethodInterceptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ClientMethodInterceptorAttribute : InterceptorAttributeAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ClientMethodInterceptorAttribute(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | public ClientMethodInterceptorAttribute() 18 | { 19 | } 20 | 21 | public override async Task Intercept(IInterceptorContext context) 22 | { 23 | Logger.LogTrace("\n------------------>Client method interceptor attribute\n"); 24 | var r = await context.Next(); 25 | return r; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/Sample.Common/ResponseResult.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.Common 2 | { 3 | public class ResponseResult 4 | { 5 | public bool Success; 6 | public T Result; 7 | public string Error; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/Sample.Common/ResultModel.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.Common 2 | { 3 | public class ResultModel 4 | { 5 | public string Message { get; set; } 6 | } 7 | 8 | public class TestModel 9 | { 10 | public int Id { get; set; } 11 | 12 | public string Name { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/Sample.Common/Sample.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/Sample.Common/ServerClassInterceptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ServerClassInterceptorAttribute : InterceptorAttributeAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ServerClassInterceptorAttribute(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | public ServerClassInterceptorAttribute() 18 | { 19 | } 20 | 21 | public override async Task Intercept(IInterceptorContext context) 22 | { 23 | Logger.LogTrace("\n------------------>Server class interceptor attribute\n"); 24 | var r = await context.Next(); 25 | return r; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/Sample.Common/ServerGlobalInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ServerGlobalInterceptor : InterceptorAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ServerGlobalInterceptor(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | 18 | public override async Task Intercept(IInterceptorContext context) 19 | { 20 | 21 | Logger.LogTrace("\n---------------->Server global interceptor\n"); 22 | return await context.Next(); 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/Sample.Common/ServerInterceptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ServerInterceptorAttribute : InterceptorAttributeAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ServerInterceptorAttribute(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | public ServerInterceptorAttribute() 18 | { 19 | } 20 | 21 | public override async Task Intercept(IInterceptorContext context) 22 | { 23 | Logger.LogTrace("\n------------------>Server Interceptor attribute\n"); 24 | var r = await context.Next(); 25 | return r; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/Sample.Common/ServerMethodInterceptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | 6 | namespace Sample.Common 7 | { 8 | public class ServerMethodInterceptorAttribute : InterceptorAttributeAbstract 9 | { 10 | private ILogger Logger { get; } 11 | 12 | public ServerMethodInterceptorAttribute(ILogger logger) 13 | { 14 | Logger = logger; 15 | } 16 | 17 | public ServerMethodInterceptorAttribute() 18 | { 19 | } 20 | 21 | public override async Task Intercept(IInterceptorContext context) 22 | { 23 | Logger.LogTrace("\n------------------>Server method interceptor attribute\n"); 24 | var r = await context.Next(); 25 | return r; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/Sample.Server/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Sample.Service.Interfaces; 7 | using Uragano.Core; 8 | 9 | namespace Sample.Server.Controllers 10 | { 11 | [Route("api/[controller]")] 12 | [ApiController] 13 | public class ValuesController : ControllerBase 14 | { 15 | private IHelloService HelloService { get; } 16 | 17 | public ValuesController(IHelloService helloService, IServiceProvider serviceProvider) 18 | { 19 | HelloService = helloService; 20 | var s = serviceProvider.GetServices(); 21 | } 22 | 23 | // GET api/values 24 | [HttpGet] 25 | public async Task Get() 26 | { 27 | 28 | //await HelloService.SayHello(); 29 | return Ok(new 30 | { 31 | name = await HelloService.SetMeta(("token", "bearer ....."), ("x-consistent-hash-key", Guid.NewGuid().ToString())).SayHello(Guid.NewGuid().ToString()), 32 | //Reply = await HelloService.SayHello("Owen"), 33 | //entity = await HelloService.SayHello(new TestModel { Id = 1, Name = "owen" }), 34 | //gen = await HelloService.Test() 35 | 36 | }); 37 | } 38 | 39 | // GET api/values/5 40 | [HttpGet("{id}")] 41 | public ActionResult Get(int id) 42 | { 43 | return "value"; 44 | } 45 | 46 | // POST api/values 47 | [HttpPost] 48 | public void Post([FromBody] string value) 49 | { 50 | } 51 | 52 | // PUT api/values/5 53 | [HttpPut("{id}")] 54 | public void Put(int id, [FromBody] string value) 55 | { 56 | } 57 | 58 | // DELETE api/values/5 59 | [HttpDelete("{id}")] 60 | public void Delete(int id) 61 | { 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /samples/Sample.Server/HelloService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Sample.Common; 4 | using Sample.Service.Interfaces; 5 | using Uragano.Abstractions; 6 | 7 | namespace Sample.Server 8 | { 9 | 10 | [ServerClassInterceptor] 11 | [ServerInterceptor] 12 | public class HelloService : IHelloService 13 | { 14 | [NonIntercept] 15 | [ServerMethodInterceptor] 16 | public async Task SayHello(string name) 17 | { 18 | //await Task.Delay(5000); 19 | return await Task.FromResult(new ResultModel { Message = name }); 20 | } 21 | 22 | public async Task SayHello(TestModel testModel) 23 | { 24 | return await Task.FromResult(new ResultModel 25 | { 26 | Message = "Rec " + testModel.Name 27 | }); 28 | } 29 | 30 | public async Task SayHello() 31 | { 32 | 33 | } 34 | 35 | public async Task Age() 36 | { 37 | //await Task.Delay(2000); 38 | return await Task.FromResult(18); 39 | } 40 | 41 | public async Task> Test() 42 | { 43 | return await Task.FromResult(new ResponseResult 44 | { 45 | Success = true, 46 | Result = "OK" 47 | }); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/Sample.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Sample.Server 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args).UseStartup(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /samples/Sample.Server/Sample.Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | a309b84e-3fcf-40ea-a807-a76a4def865a 7 | latest 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/Sample.Server/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Sample.Common; 8 | using Uragano.Abstractions; 9 | using Uragano.Caching.Redis; 10 | using Uragano.Consul; 11 | using Uragano.Core; 12 | using Uragano.Logging.Exceptionless; 13 | using Uragano.Remoting.LoadBalancing; 14 | using Uragano.ZooKeeper; 15 | using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; 16 | 17 | namespace Sample.Server 18 | { 19 | public class Startup 20 | { 21 | public Startup(IConfiguration configuration) 22 | { 23 | Configuration = configuration; 24 | } 25 | 26 | public IConfiguration Configuration { get; } 27 | 28 | // This method gets called by the runtime. Use this method to add services to the container. 29 | public void ConfigureServices(IServiceCollection services) 30 | { 31 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 32 | services.AddUragano(Configuration, builder => 33 | { 34 | 35 | builder.AddClient(); 36 | builder.AddServer(); 37 | //builder.AddZooKeeper(); 38 | builder.AddConsul(); 39 | builder.AddClientGlobalInterceptor(); 40 | builder.AddServerGlobalInterceptor(); 41 | //builder.AddExceptionlessLogger(); 42 | //builder.AddLog4NetLogger(); 43 | //builder.AddNLogLogger(); 44 | //builder.AddRedisPartitionCaching(); 45 | //builder.AddRedisCaching(); 46 | //builder.AddMemoryCaching(); 47 | builder.AddCircuitBreaker(); 48 | builder.AddOption(UraganoOptions.Remoting_Invoke_CancellationTokenSource_Timeout, TimeSpan.FromSeconds(60)); 49 | builder.AddOptions(); 50 | }); 51 | } 52 | 53 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 54 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 55 | { 56 | if (env.IsDevelopment()) 57 | { 58 | app.UseDeveloperExceptionPage(); 59 | } 60 | 61 | app.UseMvc(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /samples/Sample.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace", 5 | "System": "Warning", 6 | "Microsoft": "Warning" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/Sample.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*", 8 | "Uragano": { 9 | "Server": { 10 | "address": "192.168.1.129", 11 | "port": 5001, 12 | "weight": 1 13 | }, 14 | "Client": { 15 | "DefaultCert": { 16 | 17 | }, 18 | "ServicesCert": { 19 | 20 | } 21 | }, 22 | "ServiceDiscovery": { 23 | "Consul": { 24 | "Client": { 25 | "Address": "http://192.168.1.254:8500", 26 | "Token": "5ece74af-19d1-0e61-b25c-b9665d29f50b", 27 | "datacenter": "dc1", 28 | "timeout": 10 29 | }, 30 | "Service": { 31 | "Id": null, 32 | "Name": "RPC", 33 | "tags": null, 34 | "EnableTagOverride": false, 35 | "meta": null, 36 | "HealthCheckInterval": 10 37 | } 38 | }, 39 | "ZooKeeper": { 40 | "Client": { 41 | "ConnectionString": "localhost:2181", 42 | "SessionTimeout": 10000, 43 | "CanBeReadOnly": false 44 | }, 45 | "Service": { 46 | "Name": "RPC", 47 | "Id": null 48 | } 49 | } 50 | }, 51 | "CircuitBreaker": { 52 | "Polly": { 53 | "timeout": 1000, 54 | "retry": 1, 55 | "ExceptionsAllowedBeforeBreaking": 10, 56 | "DurationOfBreak": 60000, 57 | "MaxParallelization": 10, 58 | "MaxQueuingActions": 0 59 | } 60 | }, 61 | "Caching": { 62 | "Redis": { 63 | "KeyPrefix": "Uragano", 64 | "ExpireSeconds": 3600, 65 | "ConnectionStrings": [ 66 | { 67 | "Host": "192.168.1.254", 68 | "Port": 6379, 69 | "Password": "nihao123", 70 | "DefaultDatabase": 13, 71 | "PoolSize": 50, 72 | "SSL": false, 73 | "ConnectionTimeout": -1, 74 | "PreHeat": true, 75 | "WriteBuffer": 10240, 76 | "TryIt": 0, 77 | "Name": "" 78 | }, 79 | { 80 | "Host": "192.168.1.253", 81 | "Port": 6379, 82 | "Password": "nihao123", 83 | "DefaultDatabase": 13, 84 | "PoolSize": 50, 85 | "SSL": false, 86 | "ConnectionTimeout": -1, 87 | "PreHeat": true, 88 | "WriteBuffer": 10240, 89 | "TryIt": 0, 90 | "Name": "" 91 | } 92 | ] 93 | }, 94 | "Memory": { 95 | "ExpireSeconds": 60 96 | } 97 | }, 98 | "Logging": { 99 | "Exceptionless": { 100 | "apiKey": "avtkum3kDogGmLjMCQim9wgC8zHDbcrzQEpDNNJ7", 101 | "ServerUrl": "" 102 | } 103 | }, 104 | "Options": { 105 | "ThreadPool_MinThreads": 100, 106 | "DotNetty_Event_Loop_Count": 100, 107 | "Output_DynamicProxy_SourceCode": true 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /samples/Sample.Server/log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/Sample.Server/nlog.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 10 | 11 | 12 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ClientGlobal_2_Interceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ClientGlobal_2_Interceptor : InterceptorAbstract 11 | { 12 | private ILogger Logger { get; } 13 | 14 | public ClientGlobal_2_Interceptor(ILogger logger) 15 | { 16 | Logger = logger; 17 | } 18 | 19 | 20 | public override async Task Intercept(IInterceptorContext context) 21 | { 22 | Logger.LogDebug("\n---------------->Client global interceptor\n"); 23 | return await context.Next(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ClientInterceptor_1_Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ClientInterceptor_1_Attribute : InterceptorAttributeAbstract 11 | { 12 | public ClientInterceptor_1_Attribute() { } 13 | private ILogger Logger { get; } 14 | 15 | public ClientInterceptor_1_Attribute(ILogger logger) 16 | { 17 | Logger = logger; 18 | } 19 | public override async Task Intercept(IInterceptorContext context) 20 | { 21 | Logger.LogDebug("\n--------------->Client interceptor attribute\n"); 22 | return await context.Next(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ClientInterceptor_2_Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ClientInterceptor_2_Attribute : InterceptorAttributeAbstract 11 | { 12 | public ClientInterceptor_2_Attribute() { } 13 | private ILogger Logger { get; } 14 | 15 | public ClientInterceptor_2_Attribute(ILogger logger) 16 | { 17 | Logger = logger; 18 | } 19 | public override async Task Intercept(IInterceptorContext context) 20 | { 21 | Logger.LogDebug("\n--------------->Client interceptor attribute\n"); 22 | return await context.Next(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ClientMethodInterceptor_1_Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ClientMethodInterceptor_1_Attribute : InterceptorAttributeAbstract 11 | { 12 | public ClientMethodInterceptor_1_Attribute() { } 13 | private ILogger Logger { get; } 14 | 15 | public ClientMethodInterceptor_1_Attribute(ILogger logger) 16 | { 17 | Logger = logger; 18 | } 19 | public override async Task Intercept(IInterceptorContext context) 20 | { 21 | Logger.LogDebug("\n--------------->Client interceptor attribute\n"); 22 | return await context.Next(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ClientMethodInterceptor_2_Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ClientMethodInterceptor_2_Attribute : InterceptorAttributeAbstract 11 | { 12 | public ClientMethodInterceptor_2_Attribute() { } 13 | private ILogger Logger { get; } 14 | 15 | public ClientMethodInterceptor_2_Attribute(ILogger logger) 16 | { 17 | Logger = logger; 18 | } 19 | public override async Task Intercept(IInterceptorContext context) 20 | { 21 | Logger.LogDebug("\n--------------->Client interceptor attribute\n"); 22 | return await context.Next(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/IHelloService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Sample.Common; 4 | using Uragano.Abstractions; 5 | 6 | namespace Sample.Service.Interfaces 7 | { 8 | [ServiceDiscoveryName("RPC")] 9 | [ServiceRoute("hello")] 10 | [ClientClassInterceptor] 11 | 12 | public interface IHelloService : IService 13 | { 14 | [NonIntercept] 15 | [ClientMethodInterceptor] 16 | [CircuitBreaker(FallbackExecuteScript = "return new ResultModel{Message=\"fallback\"};", ScriptUsingNameSpaces = new[] { "Sample.Common" })] 17 | [Caching(Key = "customKey:{0}", ExpireSeconds = 30)] 18 | [ServiceRoute("say/async")] 19 | Task SayHello(string name); 20 | 21 | [ServiceRoute("say/async/entity")] 22 | Task SayHello(TestModel testModel); 23 | 24 | [ServiceRoute("say/task")] 25 | Task SayHello(); 26 | 27 | [ServiceRoute("say/int")] 28 | Task Age(); 29 | 30 | Task> Test(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/IPersonService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Uragano.Abstractions; 6 | 7 | namespace Sample.Service.Interfaces 8 | { 9 | [ServiceDiscoveryName("PersionService")] 10 | [ServiceRoute("persion")] 11 | 12 | public interface IPersonService : IService 13 | { 14 | [ServiceRoute("getname")] 15 | [CircuitBreaker(FallbackExecuteScript = "return new{name=\"fall\"};", Retry = 2, TimeoutMilliseconds = 1000, MaxParallelization = 1, ExceptionsAllowedBeforeBreaking = 10)] 16 | Task GetName(int id); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/Sample.Service.Interfaces.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/Sample.Service.Interfaces/ServerGlobalInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Uragano.Abstractions; 5 | using Uragano.DynamicProxy.Interceptor; 6 | using Uragano.Remoting; 7 | 8 | namespace Sample.Service.Interfaces 9 | { 10 | public class ServerGlobalInterceptor : InterceptorAbstract 11 | { 12 | private ILogger Logger { get; } 13 | 14 | public ServerGlobalInterceptor(ILogger logger) 15 | { 16 | Logger = logger; 17 | } 18 | public override async Task Intercept(IInterceptorContext context) 19 | { 20 | Logger.LogDebug("\n---------------->Server global interceptor\n"); 21 | return await context.Next(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Sample.Service.Interfaces; 8 | using Uragano.Abstractions; 9 | using Uragano.Core; 10 | 11 | 12 | namespace Sample.WebApi.Controllers 13 | { 14 | [Route("api/[controller]")] 15 | [ApiController] 16 | public class ValuesController : ControllerBase 17 | { 18 | private IHelloService HelloService { get; } 19 | 20 | private IServiceProvider ServiceProvider { get; } 21 | 22 | private IPersonService PersonService { get; } 23 | 24 | public ValuesController(IHelloService helloService, IServiceProvider serviceProvider, IPersonService personService) 25 | { 26 | HelloService = helloService; 27 | ServiceProvider = serviceProvider; 28 | PersonService = personService; 29 | } 30 | 31 | // GET api/values 32 | [HttpGet] 33 | public async Task Get() 34 | { 35 | return Ok(await PersonService.GetName(1)); 36 | var a = Guid.NewGuid().ToString(); 37 | //var r = ServiceProvider.GetServices(); 38 | var r = await HelloService.SetMeta(("token", "bearer .....")).SayHello(a); 39 | if (r.Message == a) 40 | return Ok(r); 41 | return BadRequest(new 42 | { 43 | @in = a, 44 | @out = r.Message 45 | }); 46 | } 47 | 48 | // GET api/values/5 49 | [HttpGet("{id}")] 50 | public ActionResult Get(int id) 51 | { 52 | return "value"; 53 | } 54 | 55 | // POST api/values 56 | [HttpPost] 57 | public void Post([FromBody] string value) 58 | { 59 | } 60 | 61 | // PUT api/values/5 62 | [HttpPut("{id}")] 63 | public void Put(int id, [FromBody] string value) 64 | { 65 | } 66 | 67 | // DELETE api/values/5 68 | [HttpDelete("{id}")] 69 | public void Delete(int id) 70 | { 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/MyInterceptor1Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | using Uragano.Remoting; 6 | 7 | namespace Sample.WebApi 8 | { 9 | public class MyInterceptor1Attribute : InterceptorAttributeAbstract 10 | { 11 | public override async Task Intercept(IInterceptorContext context) 12 | { 13 | return await context.Next(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/MyInterceptor2Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | using Uragano.Remoting; 6 | 7 | namespace Sample.WebApi 8 | { 9 | public class MyInterceptor2Attribute : InterceptorAttributeAbstract 10 | { 11 | public override async Task Intercept(IInterceptorContext context) 12 | { 13 | return await context.Next(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/MyInterceptor3Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | using Uragano.Remoting; 6 | 7 | namespace Sample.WebApi 8 | { 9 | public class MyInterceptor3Attribute : InterceptorAttributeAbstract 10 | { 11 | public override async Task Intercept(IInterceptorContext context) 12 | { 13 | return await context.Next(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/MyInterceptor4Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | using Uragano.Remoting; 6 | 7 | namespace Sample.WebApi 8 | { 9 | public class MyInterceptor4Attribute : InterceptorAttributeAbstract 10 | { 11 | public override async Task Intercept(IInterceptorContext context) 12 | { 13 | return await context.Next(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Sample.WebApi 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Sample.WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Sample.Common; 8 | using Sample.Service.Interfaces; 9 | using Uragano.Abstractions; 10 | using Uragano.Codec.MessagePack; 11 | using Uragano.Consul; 12 | using Uragano.Core; 13 | using Uragano.DynamicProxy; 14 | 15 | namespace Sample.WebApi 16 | { 17 | public class Startup 18 | { 19 | public Startup(IConfiguration configuration) 20 | { 21 | Configuration = configuration; 22 | } 23 | 24 | public IConfiguration Configuration { get; } 25 | 26 | // This method gets called by the runtime. Use this method to add services to the container. 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | 30 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 31 | //services.AddUragano(Configuration.GetSection("Uragano")); 32 | services.AddUragano(Configuration, builder => 33 | { 34 | builder.AddConsul(); 35 | builder.AddClient(); 36 | //builder.AddCircuitBreaker(1000); 37 | builder.AddCircuitBreaker(); 38 | //builder.DependencyServices(("RPC", "", "")); 39 | //builder.DependencyServices(Configuration.GetSection("Uragano:DependencyServices")); 40 | //builder.Option(UraganoOptions.Client_Node_Status_Refresh_Interval, TimeSpan.FromSeconds(10)); 41 | builder.AddOptions(); 42 | }); 43 | } 44 | 45 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 46 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 47 | { 48 | if (env.IsDevelopment()) 49 | { 50 | app.UseDeveloperExceptionPage(); 51 | } 52 | 53 | app.UseMvc(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Test1Interceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy.Interceptor; 5 | using Uragano.Remoting; 6 | 7 | namespace Sample.WebApi 8 | { 9 | public class Test1Interceptor : InterceptorAbstract 10 | { 11 | public override async Task Intercept(IInterceptorContext context) 12 | { 13 | Console.WriteLine("---------------->Interceptor1"); 14 | return await context.Next(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/Test2INterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Uragano.Abstractions; 6 | using Uragano.Core; 7 | using Uragano.DynamicProxy.Interceptor; 8 | using Uragano.Remoting; 9 | 10 | namespace Sample.WebApi 11 | { 12 | public class Test2Interceptor : InterceptorAbstract 13 | { 14 | public override async Task Intercept(IInterceptorContext context) 15 | { 16 | Console.WriteLine("---------------->Interceptor2"); 17 | return await context.Next(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace", 5 | "System": "Warning", 6 | "Microsoft": "Warning" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/Sample.WebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace" 5 | } 6 | }, 7 | "AllowedHosts": "*", 8 | "Uragano": { 9 | "ServiceDiscovery": { 10 | "Consul": { 11 | "ServiceDiscovery": "Uragano.Consul.ConsulServiceDiscovery", 12 | "Client": { 13 | "Address": "http://192.168.1.254:8500", 14 | "Token": "5ece74af-19d1-0e61-b25c-b9665d29f50b" 15 | }, 16 | "Service": { 17 | "Id": null, 18 | "Name": "RPC", 19 | "tags": null, 20 | "EnableTagOverride": false, 21 | "meta": null, 22 | "HealthCheckInterval": 10 23 | } 24 | } 25 | }, 26 | "CircuitBreaker": { 27 | "Polly": { 28 | "timeout": 2000, 29 | "retry": 3, 30 | "ExceptionsAllowedBeforeBreaking": 10, 31 | "DurationOfBreak": 60000, 32 | "MaxParallelization": 0, 33 | "MaxQueuingActions": 0 34 | } 35 | }, 36 | "Options": { 37 | "ThreadPool_MinThreads": 100, 38 | "DotNetty_Event_Loop_Count": 100 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CachingAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class CachingAttribute : Attribute 7 | { 8 | 9 | public string Key { get; set; } 10 | 11 | public int ExpireSeconds { get; set; } = -1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/CircuitBreakerOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions.CircuitBreaker 4 | { 5 | public class CircuitBreakerOptions 6 | { 7 | public TimeSpan Timeout { get; set; } 8 | 9 | public int Retry { get; set; } 10 | 11 | /// 12 | /// The number of exceptions or handled results that are allowed before opening the circuit. 13 | /// 14 | public int ExceptionsAllowedBeforeBreaking { get; set; } 15 | 16 | /// 17 | /// The duration the circuit will stay open before resetting. 18 | /// 19 | public TimeSpan DurationOfBreak { get; set; } = TimeSpan.FromMinutes(1); 20 | 21 | 22 | public int MaxParallelization { get; set; } = 0; 23 | 24 | public int MaxQueuingActions { get; set; } = 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/ICircuitBreaker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Uragano.Abstractions.CircuitBreaker 5 | { 6 | public interface ICircuitBreaker 7 | { 8 | Task ExecuteAsync(string route, Func> action, Type returnValueType); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/ICircuitBreakerEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Threading.Tasks; 4 | 5 | namespace Uragano.Abstractions.CircuitBreaker 6 | { 7 | public interface ICircuitBreakerEvent 8 | { 9 | Task OnFallback(string route, MethodInfo methodInfo); 10 | 11 | Task OnBreak(string route, MethodInfo methodInfo, Exception exception, TimeSpan time); 12 | 13 | Task OnRest(string route, MethodInfo methodInfo); 14 | 15 | Task OnHalfOpen(string route, MethodInfo methodInfo); 16 | 17 | Task OnTimeOut(string route, MethodInfo methodInfo, Exception exception); 18 | 19 | Task OnRetry(string route, MethodInfo methodInfo, Exception exception, int retryTimes); 20 | 21 | Task OnBulkheadRejected(string route, MethodInfo methodInfo); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/IScriptInjection.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Uragano.Abstractions.CircuitBreaker 4 | { 5 | public interface IScriptInjection 6 | { 7 | bool AddScript(string route, string script, string[] usingNamespaces = default); 8 | 9 | ScriptDescriptor GetScript(string route); 10 | 11 | Task Run(string route); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/ScriptDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions.CircuitBreaker 2 | { 3 | public class ScriptDescriptor 4 | { 5 | 6 | public string Script { get; set; } 7 | public string[] UsingNamespaces { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreaker/ServiceCIrcuitBreakerOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions.CircuitBreaker 2 | { 3 | public class ServiceCircuitBreakerOptions : CircuitBreakerOptions 4 | { 5 | public bool HasInjection { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/CircuitBreakerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class CircuitBreakerAttribute : Attribute 7 | { 8 | public int TimeoutMilliseconds { get; set; } = -1; 9 | 10 | public int Retry { get; set; } = -1; 11 | 12 | /// 13 | /// The number of exceptions or handled results that are allowed before opening the circuit. 14 | /// 15 | public int ExceptionsAllowedBeforeBreaking { get; set; } = -1; 16 | 17 | /// 18 | /// The duration the circuit will stay open before resetting. 19 | /// 20 | public int DurationOfBreakSeconds { get; set; } = -1; 21 | 22 | public string FallbackExecuteScript { get; set; } 23 | 24 | public string[] ScriptUsingNameSpaces { get; set; } 25 | 26 | public int MaxParallelization { get; set; } = -1; 27 | 28 | public int MaxQueuingActions { get; set; } = -1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ConsistentHash/ConsistentHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Uragano.Abstractions.ConsistentHash 7 | { 8 | public class ConsistentHash : IConsistentHash 9 | { 10 | private SortedDictionary Ring { get; } = new SortedDictionary(); 11 | 12 | private int VirtualReplication { get; set; } 13 | 14 | public ConsistentHash(int virtualReplication = 200) 15 | { 16 | VirtualReplication = virtualReplication; 17 | } 18 | 19 | public void SetVirtualReplicationCount(int count) 20 | { 21 | VirtualReplication = count; 22 | } 23 | 24 | public List GetAllNodes() 25 | { 26 | return Ring.Select(p => p.Value).Distinct().ToList(); 27 | } 28 | 29 | public void AddNode(T node, string key) 30 | { 31 | for (var i = 0; i < VirtualReplication; i++) 32 | { 33 | var hash = HashAlgorithm.Hash(key + i); 34 | Ring.Add(hash, node); 35 | } 36 | } 37 | 38 | public void RemoveNode(string key) 39 | { 40 | for (var i = 0; i < VirtualReplication; i++) 41 | { 42 | var hash = HashAlgorithm.Hash(key + i); 43 | Ring.Remove(hash); 44 | } 45 | } 46 | 47 | public T GetNodeForKey(string key) 48 | { 49 | if (!Ring.Any()) 50 | throw new InvalidOperationException("Can not find the available nodes, please call the AddNode method to add nodes."); 51 | 52 | var hash = HashAlgorithm.Hash(key); 53 | if (Ring.ContainsKey(hash)) 54 | return Ring[hash]; 55 | var node = Ring.Where(p => p.Key > hash).OrderBy(i => i.Key).Select(p => p.Value).FirstOrDefault(); 56 | if (node != null) 57 | return node; 58 | return Ring.FirstOrDefault().Value; 59 | } 60 | } 61 | 62 | internal class HashAlgorithm 63 | { 64 | private const uint m = 0x5bd1e995; 65 | private const int r = 24; 66 | public static int Hash(byte[] data, uint seed = 0xc58f1a7b) 67 | { 68 | var length = data.Length; 69 | if (length == 0) 70 | return 0; 71 | 72 | var h = seed ^ (uint)length; 73 | var c = 0; 74 | while (length >= 4) 75 | { 76 | var k = (uint)( 77 | data[c++] 78 | | data[c++] << 8 79 | | data[c++] << 16 80 | | data[c++] << 24); 81 | k *= m; 82 | k ^= k >> r; 83 | k *= m; 84 | h *= m; 85 | h ^= k; 86 | length -= 4; 87 | } 88 | switch (length) 89 | { 90 | case 3: 91 | h ^= (ushort)(data[c++] | data[c++] << 8); 92 | h ^= (uint)(data[c] << 16); 93 | h *= m; 94 | break; 95 | case 2: 96 | h ^= (ushort)(data[c++] | data[c] << 8); 97 | h *= m; 98 | break; 99 | case 1: 100 | h ^= data[c]; 101 | h *= m; 102 | break; 103 | } 104 | 105 | h ^= h >> 13; 106 | h *= m; 107 | h ^= h >> 15; 108 | return (int)h; 109 | } 110 | 111 | public static int Hash(string data, uint seed = 0xc58f1a7b) 112 | { 113 | return Hash(Encoding.UTF8.GetBytes(data), seed); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ConsistentHash/IConsistentHash.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Uragano.Abstractions.ConsistentHash 4 | { 5 | public interface IConsistentHash 6 | { 7 | void SetVirtualReplicationCount(int count); 8 | 9 | List GetAllNodes(); 10 | 11 | void AddNode(T node, string key); 12 | 13 | void RemoveNode(string key); 14 | 15 | T GetNodeForKey(string key); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/EnvironmentVariableReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | public class EnvironmentVariableReader 7 | { 8 | public static T Get(string variable, T defaultValue = default) 9 | { 10 | var value = Environment.GetEnvironmentVariable(variable); 11 | if (string.IsNullOrWhiteSpace(value)) 12 | return defaultValue; 13 | 14 | value = value.ReplaceIpPlaceholder(); 15 | 16 | var matches = Regex.Matches(value, "[{](.*?)[}]"); 17 | if (matches.Count > 0) 18 | { 19 | foreach (var match in matches) 20 | { 21 | value = value.Replace(match.ToString(), Environment.GetEnvironmentVariable(match.ToString().TrimStart('{').TrimEnd('}'))); 22 | } 23 | } 24 | return (T)Convert.ChangeType(value, typeof(T)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/EnvironmentVariables.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions 2 | { 3 | public class EnvironmentVariables 4 | { 5 | public const string uragano_server_addr = "uragano_server_addr"; 6 | 7 | public const string uragano_server_port = "uragano_server_port"; 8 | 9 | public const string uragano_server_weight = "uragano_server_weight"; 10 | 11 | public const string uragano_service_id = "uragano_service_id"; 12 | 13 | public const string uragano_service_name = "uragano_service_name"; 14 | 15 | public const string uragano_consul_addr = "uragano_consul_addr"; 16 | 17 | public const string uragano_consul_token = "uragano_consul_token"; 18 | 19 | public const string uragano_consul_dc = "uragano_consul_dc"; 20 | 21 | public const string uragano_consul_timeout = "uragano_consul_timeout"; 22 | 23 | public const string uragano_consul_hc_interval = "uragano_consul_hc_interval"; 24 | 25 | public const string uragano_zk_addr = "uragano_zk_addr"; 26 | 27 | public const string uragano_zk_session_timeout = "uragano_zk_session_timeout"; 28 | 29 | public const string uragano_zk_readonly = "uragano_zk_readonly"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Exceptions/DuplicateRouteException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions.Exceptions 4 | { 5 | public class DuplicateRouteException : Exception 6 | { 7 | public DuplicateRouteException(string route) : base($"Duplicate route {route}.") 8 | { 9 | 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Exceptions/NotFoundNodeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions.Exceptions 4 | { 5 | public class NotFoundNodeException : Exception 6 | { 7 | public string ServiceName { get; } 8 | 9 | public NotFoundNodeException(string serviceName) : base($"Service {serviceName} did not found available nodes.") 10 | { 11 | ServiceName = serviceName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Exceptions/NotFoundRouteException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions.Exceptions 4 | { 5 | public class NotFoundRouteException : Exception 6 | { 7 | public NotFoundRouteException(string route) : base($"Route {route} not found.") 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Exceptions/RemoteInvokeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions.Exceptions 4 | { 5 | public class RemoteInvokeException : Exception 6 | { 7 | public RemoteInvokeException(string route, string message, RemotingStatus status) : base($"Remote call exception(route:{route}):{message}") 8 | { 9 | Route = route; 10 | RemotingStatus = status; 11 | } 12 | 13 | public string Route { get; } 14 | 15 | public RemotingStatus RemotingStatus { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ICaching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | public interface ICaching 7 | { 8 | Task Set(string key, TValue value, int expireSeconds = -1); 9 | 10 | Task<(object value, bool hasKey)> Get(string key, Type type); 11 | 12 | Task<(TValue value, bool hasKey)> Get(string key); 13 | 14 | Task Remove(params string[] keys); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ICachingKeyGenerator.Default.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | 6 | namespace Uragano.Abstractions 7 | { 8 | public class CachingKeyGenerator : ICachingKeyGenerator 9 | { 10 | private ICodec Codec { get; } 11 | 12 | 13 | public CachingKeyGenerator(ICodec codec) 14 | { 15 | Codec = codec; 16 | } 17 | 18 | private const string LinkString = ":"; 19 | 20 | public string GenerateKeyPlaceholder(string keyPrefix, int globalExpire, string route, MethodInfo methodInfo, CachingAttribute cachingAttribute = default) 21 | { 22 | var sb = new StringBuilder(); 23 | if (!string.IsNullOrWhiteSpace(keyPrefix)) 24 | sb.AppendFormat("{0}{1}", keyPrefix, LinkString); 25 | if (cachingAttribute == null || string.IsNullOrWhiteSpace(cachingAttribute.Key)) 26 | { 27 | sb.AppendFormat("{0}", route); 28 | if (methodInfo.GetParameters().Length > 0) 29 | sb.Append(LinkString + "{0}"); 30 | } 31 | else 32 | sb.Append(cachingAttribute.Key); 33 | 34 | return sb.ToString(); 35 | } 36 | 37 | public string ReplacePlaceholder(string keyPlaceholder, bool customKey, object[] args) 38 | { 39 | if (args == null || args.Length <= 0) return keyPlaceholder; 40 | return customKey ? string.Format(keyPlaceholder, args) : string.Format(keyPlaceholder, MD5(Codec.Serialize(args))); 41 | } 42 | 43 | private string MD5(byte[] bytes) 44 | { 45 | using (MD5 md5 = new MD5CryptoServiceProvider()) 46 | { 47 | var hash = md5.ComputeHash(bytes); 48 | md5.Clear(); 49 | return BitConverter.ToString(hash).Replace("-", "").ToLower(); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ICachingKeyGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public interface ICachingKeyGenerator 6 | { 7 | string GenerateKeyPlaceholder(string keyPrefix, int globalExpire, string route, MethodInfo methodInfo, CachingAttribute cachingAttribute = default); 8 | 9 | string ReplacePlaceholder(string keyPlaceholder, bool customKey, object[] args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ICachingOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public interface ICachingOptions 6 | { 7 | string KeyPrefix { get; set; } 8 | int ExpireSeconds { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ICodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public interface ICodec 6 | { 7 | byte[] Serialize(TData data); 8 | 9 | object Deserialize(byte[] data, Type type); 10 | 11 | T Deserialize(byte[] data); 12 | 13 | string ToJson(TData data); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public interface IInterceptor 6 | { 7 | Task Intercept(IInterceptorContext context); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IInterceptorContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Threading.Tasks; 5 | 6 | namespace Uragano.Abstractions 7 | { 8 | public interface IInterceptorContext 9 | { 10 | string ServiceRoute { get; } 11 | 12 | Dictionary Meta { get; } 13 | 14 | object[] Args { get; } 15 | 16 | IServiceProvider ServiceProvider { get; } 17 | 18 | MethodInfo MethodInfo { get; } 19 | 20 | Task Next(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IInvokeMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MessagePack; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | [Union(0, typeof(InvokeMessage))] 7 | public interface IInvokeMessage 8 | { 9 | 10 | [Key(0)] 11 | string Route { get; set; } 12 | 13 | [Key(1)] 14 | object[] Args { get; set; } 15 | 16 | [Key(2)] 17 | Dictionary Meta { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ILoadBalancing.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions.ServiceDiscovery; 4 | 5 | namespace Uragano.Abstractions 6 | { 7 | public interface ILoadBalancing 8 | { 9 | Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, IReadOnlyDictionary serviceMeta); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IPHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Net; 3 | using System.Net.NetworkInformation; 4 | using System.Net.Sockets; 5 | 6 | namespace Uragano.Abstractions 7 | { 8 | public static class IpHelper 9 | { 10 | private static readonly long IpABegin, IpAEnd, IpBBegin, IpBEnd, IpCBegin, IpCEnd; 11 | private const string LocalIp = "{LOCALIP}"; 12 | static IpHelper() 13 | { 14 | IpABegin = ConvertIpToNumber(IPAddress.Parse("192.168.0.0")); 15 | IpAEnd = ConvertIpToNumber(IPAddress.Parse("192.168.255.255")); 16 | 17 | IpBBegin = ConvertIpToNumber(IPAddress.Parse("172.16.0.0")); 18 | IpBEnd = ConvertIpToNumber(IPAddress.Parse("172.31.255.255")); 19 | 20 | IpCBegin = ConvertIpToNumber(IPAddress.Parse("10.0.0.0")); 21 | IpCEnd = ConvertIpToNumber(IPAddress.Parse("10.255.255.255")); 22 | } 23 | 24 | public static IPAddress GetLocalInternetIp() 25 | { 26 | return NetworkInterface 27 | .GetAllNetworkInterfaces() 28 | .Select(p => p.GetIPProperties()) 29 | .SelectMany(p => 30 | p.UnicastAddresses 31 | ).FirstOrDefault(p => p.Address.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(p.Address) && InternalIp(p.Address))?.Address; 32 | } 33 | 34 | private static long ConvertIpToNumber(IPAddress ipAddress) 35 | { 36 | var bytes = ipAddress.GetAddressBytes(); 37 | return bytes[0] * 256 * 256 * 256 + bytes[1] * 256 * 256 + bytes[2] * 256 + bytes[3]; 38 | } 39 | 40 | private static bool InternalIp(IPAddress iPAddress) 41 | { 42 | var num = ConvertIpToNumber(iPAddress); 43 | return num >= IpABegin && num <= IpAEnd || num >= IpBBegin && num <= IpBEnd || 44 | num >= IpCBegin && num <= IpCEnd; 45 | } 46 | 47 | public static string ReplaceIpPlaceholder(this string text) 48 | { 49 | if (!text.Contains(LocalIp)) 50 | return text; 51 | return text.Replace(LocalIp, GetLocalInternetIp().ToString()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IRemotingInvoke.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | public interface IRemotingInvoke 7 | { 8 | Task InvokeAsync(object[] args, string route, string serviceName, Dictionary meta = default); 9 | 10 | Task InvokeAsync(object[] args, string route, string serviceName, Dictionary meta = default); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public interface IService 6 | { 7 | //void SetMeta(Dictionary meta); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/IServiceResult.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [Union(0, typeof(ServiceResult))] 6 | public interface IServiceResult 7 | { 8 | [Key(0)] 9 | object Result { get; set; } 10 | 11 | [Key(1)] 12 | RemotingStatus Status { get; set; } 13 | } 14 | 15 | public enum RemotingStatus 16 | { 17 | Ok = 200, 18 | NotFound = 404, 19 | Error = 500, 20 | Unauthorized = 401, 21 | Forbidden = 403, 22 | Timeout = 504 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ITransportMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions 2 | { 3 | public interface ITransportMessage 4 | { 5 | string Id { get; set; } 6 | 7 | T Body { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/InvokeMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MessagePack; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | [MessagePackObject] 7 | public class InvokeMessage : IInvokeMessage 8 | { 9 | public InvokeMessage() 10 | { 11 | } 12 | 13 | public InvokeMessage(string route, object[] args, Dictionary meta) 14 | { 15 | Route = route; 16 | Meta = meta; 17 | Args = args; 18 | } 19 | 20 | [Key(0)] 21 | public string Route { get; set; } 22 | 23 | 24 | [Key(1)] 25 | public object[] Args { get; set; } 26 | 27 | 28 | [Key(2)] 29 | public Dictionary Meta { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/NonCachingAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)] 6 | public class NonCachingAttribute : Attribute 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/NonCircuitBreakerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | public class NonCircuitBreakerAttribute : Attribute 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/NonInterceptAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)] 6 | public class NonInterceptAttribute : Attribute 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Service/IMethodInvoker.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Uragano.Abstractions.Service 4 | { 5 | public interface IMethodInvoker 6 | { 7 | Task InvokeAsync(object instance, params object[] args); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Service/IServiceFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Threading.Tasks; 5 | 6 | namespace Uragano.Abstractions.Service 7 | { 8 | public interface IServiceFactory 9 | { 10 | void Create(string route, MethodInfo serverMethodInfo, MethodInfo clientMethodInfo, List serverInterceptors, List clientInterceptors); 11 | 12 | ServiceDescriptor Get(string route); 13 | 14 | Task InvokeAsync(string route, object[] args, Dictionary meta); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Uragano.Abstractions.CircuitBreaker; 5 | using Uragano.Abstractions.Service; 6 | 7 | namespace Uragano.Abstractions 8 | { 9 | public class ServiceDescriptor 10 | { 11 | public ServiceDescriptor(string route, MethodInfo serverMethodInfo, MethodInfo clientMethodInfo, IMethodInvoker methodInvoker, List serverInterceptors, List clientInterceptors, ServiceCircuitBreakerOptions serviceCircuitBreakerOptions, CachingConfig cachingConfig) 12 | { 13 | Route = route; 14 | ServerMethodInfo = serverMethodInfo; 15 | ClientMethodInfo = clientMethodInfo; 16 | MethodInvoker = methodInvoker; 17 | ServerInterceptors = serverInterceptors; 18 | ClientInterceptors = clientInterceptors; 19 | ServiceCircuitBreakerOptions = serviceCircuitBreakerOptions; 20 | CachingConfig = cachingConfig; 21 | } 22 | public string Route { get; } 23 | 24 | public MethodInfo ServerMethodInfo { get; } 25 | 26 | public MethodInfo ClientMethodInfo { get; } 27 | 28 | public IMethodInvoker MethodInvoker { get; } 29 | 30 | public List ServerInterceptors { get; } 31 | 32 | public List ClientInterceptors { get; } 33 | 34 | public ServiceCircuitBreakerOptions ServiceCircuitBreakerOptions { get; } 35 | 36 | public CachingConfig CachingConfig { get; } 37 | } 38 | 39 | 40 | public class CachingConfig 41 | { 42 | public CachingConfig(string keyPlaceholder, bool customKey, int expireSeconds = -1) 43 | { 44 | KeyPlaceholder = keyPlaceholder; 45 | CustomKey = customKey; 46 | ExpireSeconds = expireSeconds; 47 | } 48 | public string KeyPlaceholder { get; } 49 | 50 | public bool CustomKey { get; } 51 | 52 | public int ExpireSeconds { get; } = -1; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDiscovery/IServiceDiscovery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Uragano.Abstractions.ServiceDiscovery 6 | { 7 | public delegate void NodeJoinHandler(string serviceName, IReadOnlyList nodes); 8 | 9 | public delegate void NodeLeaveHandler(string serviceName, IReadOnlyList nodes); 10 | public interface IServiceDiscovery 11 | { 12 | event NodeLeaveHandler OnNodeLeave; 13 | event NodeJoinHandler OnNodeJoin; 14 | 15 | Task RegisterAsync(CancellationToken cancellationToken = default); 16 | 17 | Task DeregisterAsync(); 18 | 19 | Task> QueryServiceAsync(string serviceName, CancellationToken cancellationToken = default); 20 | 21 | IReadOnlyDictionary> GetAllService(); 22 | 23 | Task> GetServiceNodes(string serviceName); 24 | 25 | Task NodeMonitor(CancellationToken cancellationToken = default); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDiscovery/IServiceDiscoveryClientConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions.ServiceDiscovery 2 | { 3 | public interface IServiceDiscoveryClientConfiguration 4 | { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDiscovery/IServiceRegisterConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Abstractions.ServiceDiscovery 2 | { 3 | public interface IServiceRegisterConfiguration 4 | { 5 | string Id { get; set; } 6 | string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDiscovery/ServiceDiscoveryInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | 4 | namespace Uragano.Abstractions.ServiceDiscovery 5 | { 6 | public class ServiceDiscoveryBase 7 | { 8 | public ServiceDiscoveryBase(string address, int port, bool enableTls, IDictionary meta) 9 | { 10 | Address = address; 11 | Port = port; 12 | EnableTls = enableTls; 13 | Meta = meta; 14 | } 15 | 16 | public string Address { get; } 17 | 18 | public int Port { get; } 19 | 20 | public bool EnableTls { get; } 21 | 22 | public IDictionary Meta { get; } 23 | } 24 | 25 | public class ServiceDiscoveryInfo : ServiceDiscoveryBase 26 | { 27 | public ServiceDiscoveryInfo(string serviceId, string address, int port, int weight, bool enableTls, IDictionary meta) : base(address, port, enableTls, meta) 28 | { 29 | ServiceId = serviceId; 30 | Weight = weight; 31 | } 32 | 33 | public string ServiceId { get; } 34 | 35 | public int Weight { get; } 36 | } 37 | 38 | public class ServiceNodeInfo : ServiceDiscoveryInfo 39 | { 40 | public ServiceNodeInfo(string serviceId, string address, int port, int weight, bool enableTls, IDictionary meta) : base(serviceId, address, port, weight, enableTls, meta) 41 | { 42 | 43 | } 44 | 45 | 46 | 47 | public ConcurrentDictionary Attach { get; } = new ConcurrentDictionary(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceDiscoveryNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Interface)] 6 | public class ServiceDiscoveryNameAttribute : Attribute 7 | { 8 | public ServiceDiscoveryNameAttribute(string serviceName) 9 | { 10 | if (string.IsNullOrWhiteSpace(serviceName)) 11 | throw new ArgumentNullException(nameof(serviceName)); 12 | Name = serviceName; 13 | } 14 | 15 | public string Name { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceResult.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [MessagePackObject] 6 | public class ServiceResult : IServiceResult 7 | { 8 | public ServiceResult() 9 | { 10 | } 11 | 12 | public ServiceResult(object message, RemotingStatus status = RemotingStatus.Ok) 13 | { 14 | Result = message; 15 | Status = status; 16 | } 17 | 18 | [Key(0)] 19 | public object Result { get; set; } 20 | 21 | [Key(1)] 22 | public RemotingStatus Status { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/ServiceRouteAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)] 7 | public class ServiceRouteAttribute : Attribute 8 | { 9 | public string Route { get; set; } 10 | 11 | public ServiceRouteAttribute(string route) 12 | { 13 | if (!Regex.IsMatch(route, "^[a-zA-Z0-9/_-]+$")) 14 | throw new ArgumentException("路由只允许包含字母,数字,下划线,减号,斜杠"); 15 | Route = route; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/TransportMessage.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | 3 | namespace Uragano.Abstractions 4 | { 5 | [MessagePackObject] 6 | public class TransportMessage : ITransportMessage 7 | { 8 | [Key(0)] 9 | public string Id { get; set; } 10 | 11 | [Key(1)] 12 | public T Body { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/Uragano.Abstractions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | 0.0.4 8 | A simple, high performance RPC library. 9 | https://github.com/1100100/Uragano 10 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 11 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 12 | 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/UraganoOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Uragano.Abstractions 5 | { 6 | public class UraganoOptions 7 | { 8 | public static UraganoOption ThreadPool_MinThreads { get; } = new UraganoOption(() => 9 | { 10 | ThreadPool.GetMinThreads(out var min, out _); 11 | return min; 12 | }); 13 | 14 | public static UraganoOption ThreadPool_CompletionPortThreads { get; } = new UraganoOption(() => 15 | { 16 | ThreadPool.GetMinThreads(out _, out var completion); 17 | return completion; 18 | }); 19 | 20 | public static UraganoOption Consul_Node_Status_Refresh_Interval { get; } = 21 | new UraganoOption(TimeSpan.FromSeconds(10)); 22 | 23 | public static UraganoOption Server_DotNetty_Channel_SoBacklog { get; } = new UraganoOption(100); 24 | 25 | public static UraganoOption DotNetty_Connect_Timeout { get; } = 26 | new UraganoOption(TimeSpan.FromSeconds(1)); 27 | 28 | public static UraganoOption DotNetty_Enable_Libuv { get; } = new UraganoOption(false); 29 | 30 | public static UraganoOption DotNetty_Event_Loop_Count { get; } = new UraganoOption(() => 31 | { 32 | ThreadPool.GetMinThreads(out var min, out _); 33 | return min; 34 | }); 35 | 36 | public static UraganoOption Remoting_Invoke_CancellationTokenSource_Timeout { get; } = new UraganoOption(TimeSpan.FromSeconds(60)); 37 | 38 | public static UraganoOption Output_DynamicProxy_SourceCode { get; } = new UraganoOption(false); 39 | 40 | 41 | public static void SetOption(UraganoOption option, T value) 42 | { 43 | option.Value = value; 44 | } 45 | 46 | public static void SetOption(UraganoOption option, Func func) 47 | { 48 | option.Value = func(); 49 | } 50 | } 51 | 52 | public class UraganoOption 53 | { 54 | public UraganoOption(T value) 55 | { 56 | Value = value; 57 | } 58 | 59 | public UraganoOption(Func func) 60 | { 61 | Value = func(); 62 | } 63 | 64 | public T Value { get; internal set; } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Uragano.Abstract/UraganoSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Cryptography.X509Certificates; 4 | using Microsoft.Extensions.Logging; 5 | using Uragano.Abstractions.CircuitBreaker; 6 | 7 | namespace Uragano.Abstractions 8 | { 9 | public class UraganoSettings 10 | { 11 | public ServerSettings ServerSettings { get; set; } 12 | 13 | public ClientSettings ClientSettings { get; set; } 14 | 15 | public List ClientGlobalInterceptors { get; } = new List(); 16 | 17 | public List ServerGlobalInterceptors { get; } = new List(); 18 | 19 | public CircuitBreakerOptions CircuitBreakerOptions { get; set; } 20 | 21 | public ICachingOptions CachingOptions { get; set; } 22 | 23 | public List LoggerProviders { get; set; } = new List(); 24 | } 25 | 26 | public class ClientSettings 27 | { 28 | public CertInfo DefaultCert { get; set; } 29 | 30 | public Dictionary ServicesCert { get; set; } 31 | } 32 | 33 | public class CertInfo 34 | { 35 | public string Url { get; set; } 36 | 37 | public string Pwd { get; set; } 38 | 39 | public X509Certificate2 Cert => new X509Certificate2(Url, Pwd); 40 | } 41 | 42 | public class ServerSettings 43 | { 44 | public string Address { get; set; } = 45 | EnvironmentVariableReader.Get(EnvironmentVariables.uragano_server_addr, IpHelper.GetLocalInternetIp().ToString()); 46 | 47 | public int Port { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_server_port, 5730); 48 | 49 | public X509Certificate2 X509Certificate2 { get; set; } 50 | 51 | public int? Weight { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_server_weight, 0); 52 | 53 | public override string ToString() 54 | { 55 | return $"{Address}:{Port}"; 56 | } 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/Uragano.Caching.Memory/MemoryCaching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Caching.Memory; 4 | using Uragano.Abstractions; 5 | 6 | namespace Uragano.Caching.Memory 7 | { 8 | public class MemoryCaching : ICaching 9 | { 10 | private IMemoryCache MemoryCache { get; } 11 | 12 | public MemoryCaching(IMemoryCache memoryCache) 13 | { 14 | MemoryCache = memoryCache; 15 | } 16 | 17 | public async Task Set(string key, TValue value, int expireSeconds = -1) 18 | { 19 | var val = new MemoryCachingValue(value); 20 | if (expireSeconds <= 0) 21 | MemoryCache.Set(key, val); 22 | else 23 | MemoryCache.Set(key, val, TimeSpan.FromSeconds(expireSeconds)); 24 | await Task.CompletedTask; 25 | } 26 | 27 | public async Task<(object value, bool hasKey)> Get(string key, Type type) 28 | { 29 | var val = MemoryCache.Get(key); 30 | if (val == null) 31 | return await Task.FromResult<(object, bool)>((default, false)); 32 | return await Task.FromResult((val.Value, true)); 33 | } 34 | 35 | public async Task<(TValue value, bool hasKey)> Get(string key) 36 | { 37 | var (value, hasKey) = await Get(key, typeof(TValue)); 38 | return hasKey ? ((TValue)value, true) : (default, false); 39 | } 40 | 41 | public async Task Remove(params string[] keys) 42 | { 43 | foreach (var key in keys) 44 | { 45 | MemoryCache.Remove(key); 46 | } 47 | await Task.CompletedTask; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Memory/MemoryCachingOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.Extensions.Caching.Memory; 5 | using Uragano.Abstractions; 6 | 7 | namespace Uragano.Caching.Memory 8 | { 9 | public class MemoryCachingOptions : MemoryCacheOptions, ICachingOptions 10 | { 11 | public Type KeyGenerator { get; set; } = typeof(CachingKeyGenerator); 12 | public string KeyPrefix { get; set; } = "Uragano"; 13 | public int ExpireSeconds { get; set; } = -1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Memory/MemoryCachingValue.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Caching.Memory 2 | { 3 | public class MemoryCachingValue 4 | { 5 | public MemoryCachingValue(object value) 6 | { 7 | Value = value; 8 | } 9 | 10 | public object Value { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Memory/Uragano.Caching.Memory.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | 0.0.4 8 | Owen 9 | Owen 10 | A simple, high performance RPC library. 11 | 12 | https://github.com/1100100/Uragano 13 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 14 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Memory/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Memory; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Options; 5 | using Uragano.Abstractions; 6 | 7 | namespace Uragano.Caching.Memory 8 | { 9 | public static class UraganoBuilderExtensions 10 | { 11 | public static void AddMemoryCaching(this IUraganoBuilder builder) 12 | { 13 | var config = new MemoryCachingOptions(); 14 | builder.AddMemoryCaching(config); 15 | } 16 | 17 | public static void AddMemoryCaching(this IUraganoBuilder builder, MemoryCachingOptions memoryCachingOptions) 18 | { 19 | builder.AddCaching(memoryCachingOptions); 20 | builder.ServiceCollection.AddSingleton(new MemoryCache(Options.Create(memoryCachingOptions))); 21 | } 22 | 23 | public static void AddMemoryCaching(this IUraganoBuilder builder, IConfigurationSection configurationSection) 24 | { 25 | var config = configurationSection.Get(); 26 | builder.AddMemoryCaching(config); 27 | } 28 | 29 | public static void AddMemoryCaching(this IUraganoSampleBuilder builder) 30 | { 31 | var config = builder.Configuration.GetSection("Uragano:Caching:Memory").Get(); 32 | builder.AddMemoryCaching(config); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Redis/RedisCaching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Uragano.Abstractions; 5 | 6 | namespace Uragano.Caching.Redis 7 | { 8 | public class RedisCaching : ICaching 9 | { 10 | private ICodec Codec { get; } 11 | 12 | public RedisCaching(ICodec codec, UraganoSettings uraganoSettings) 13 | { 14 | Codec = codec; 15 | RedisHelper.Initialization(new CSRedis.CSRedisClient(((RedisOptions)uraganoSettings.CachingOptions).ConnectionStrings.First().ToString())); 16 | } 17 | 18 | public async Task Set(string key, TValue value, int expireSeconds = -1) 19 | { 20 | await RedisHelper.SetAsync(key, Codec.Serialize(value), expireSeconds); 21 | } 22 | 23 | public async Task<(object value, bool hasKey)> Get(string key, Type type) 24 | { 25 | var bytes = await RedisHelper.GetAsync(key); 26 | if (bytes == null || bytes.LongLength == 0) 27 | return (null, false); 28 | return (Codec.Deserialize(bytes, type), true); 29 | } 30 | 31 | public async Task<(TValue value, bool hasKey)> Get(string key) 32 | { 33 | var (value, hasKey) = await Get(key, typeof(TValue)); 34 | return (value == null ? default : (TValue)value, hasKey); 35 | } 36 | 37 | public async Task Remove(params string[] keys) 38 | { 39 | await RedisHelper.DelAsync(keys); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Redis/RedisOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Uragano.Abstractions; 4 | 5 | namespace Uragano.Caching.Redis 6 | { 7 | public class RedisOptions : ICachingOptions 8 | { 9 | public int ExpireSeconds { get; set; } = 3600; 10 | 11 | public string KeyPrefix { get; set; } = "Uragano"; 12 | 13 | public IEnumerable ConnectionStrings { get; set; } 14 | } 15 | 16 | public class PartitionRedisOptions : RedisOptions 17 | { 18 | public Func, RedisConnection> PartitionPolicy { get; set; } 19 | } 20 | 21 | 22 | public class RedisConnection 23 | { 24 | public RedisConnection() 25 | { 26 | } 27 | 28 | public RedisConnection(string host, int port, string password, bool ssl = false, int defaultDatabase = 1) 29 | { 30 | Host = host; 31 | Port = port; 32 | Password = password; 33 | SSL = ssl; 34 | DefaultDatabase = defaultDatabase; 35 | } 36 | 37 | public string Host { get; set; } 38 | 39 | public int Port { get; set; } = 6379; 40 | 41 | public string Password { get; set; } 42 | 43 | public int DefaultDatabase { get; set; } 44 | 45 | public int PoolSize { get; set; } = 50; 46 | 47 | public bool SSL { get; set; } 48 | 49 | public int ConnectionTimeout { get; set; } = -1; 50 | 51 | public bool PreHeat { get; set; } = true; 52 | 53 | public int WriteBuffer { get; set; } = 10240; 54 | 55 | public int TryIt { get; set; } = 0; 56 | 57 | public string Name { get; set; } 58 | 59 | public override string ToString() 60 | { 61 | return $"{Host}:{Port},password={Password},defaultDatabase={DefaultDatabase},poolsize={PoolSize},connectTimeout={ConnectionTimeout},preheat={PreHeat},ssl={SSL},writeBuffer={WriteBuffer},tryit={TryIt},name={Name}"; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Redis/RedisPartitionCaching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Caching.Distributed; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Uragano.Abstractions; 8 | using Uragano.Abstractions.ConsistentHash; 9 | 10 | namespace Uragano.Caching.Redis 11 | { 12 | public class RedisPartitionCaching : ICaching 13 | { 14 | private IDistributedCache Cache { get; } 15 | 16 | private ICodec Codec { get; } 17 | 18 | private IConsistentHash ConsistentHash { get; } 19 | 20 | public RedisPartitionCaching(UraganoSettings uraganoSettings, IServiceProvider serviceProvider, ICodec codec, IConsistentHash consistentHash) 21 | { 22 | Codec = codec; 23 | var redisOptions = (RedisOptions)uraganoSettings.CachingOptions; 24 | ConsistentHash = consistentHash; 25 | var policy = serviceProvider.GetService, RedisConnection>>(); 26 | if (policy == null) 27 | { 28 | foreach (var item in redisOptions.ConnectionStrings) 29 | { 30 | ConsistentHash.AddNode(item, item.ToString()); 31 | } 32 | policy = (key, connections) => ConsistentHash.GetNodeForKey(key); 33 | } 34 | 35 | string NodeRule(string key) 36 | { 37 | var connection = policy(key, redisOptions.ConnectionStrings); 38 | return $"{connection.Host}:{connection.Port}/{connection.DefaultDatabase}"; 39 | } 40 | 41 | RedisHelper.Initialization(new CSRedis.CSRedisClient(NodeRule, redisOptions.ConnectionStrings.Select(p => p.ToString()).ToArray())); 42 | Cache = new Microsoft.Extensions.Caching.Redis.CSRedisCache(RedisHelper.Instance); 43 | } 44 | 45 | public async Task Set(string key, TValue value, int expireSeconds = -1) 46 | { 47 | if (expireSeconds > 0) 48 | await Cache.SetAsync(key, Codec.Serialize(value), new DistributedCacheEntryOptions 49 | { 50 | AbsoluteExpirationRelativeToNow = expireSeconds <= 0 ? default : TimeSpan.FromSeconds(expireSeconds) 51 | }); 52 | else 53 | await Cache.SetAsync(key, Codec.Serialize(value)); 54 | } 55 | 56 | public async Task<(object value, bool hasKey)> Get(string key, Type type) 57 | { 58 | var bytes = await Cache.GetAsync(key); 59 | if (bytes == null || bytes.LongLength == 0) 60 | return (null, false); 61 | return (Codec.Deserialize(bytes, type), true); 62 | } 63 | 64 | public async Task<(TValue value, bool hasKey)> Get(string key) 65 | { 66 | var (value, hasKey) = await Get(key, typeof(TValue)); 67 | return (value == null ? default : (TValue)value, hasKey); 68 | } 69 | 70 | public async Task Remove(params string[] keys) 71 | { 72 | await Cache.RemoveAsync(string.Join("|", keys)); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Uragano.Caching.Redis/Uragano.Caching.Redis.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | 0.0.4 8 | Owen 9 | Owen 10 | A simple, high performance RPC library. 11 | 12 | https://github.com/1100100/Uragano 13 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 14 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Uragano.Codec.MessagePack/MessagePackCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MessagePack; 3 | using MessagePack.Resolvers; 4 | using Uragano.Abstractions; 5 | 6 | namespace Uragano.Codec.MessagePack 7 | { 8 | public class MessagePackCodec : ICodec 9 | { 10 | public MessagePackCodec() 11 | { 12 | CompositeResolver.RegisterAndSetAsDefault(NativeDateTimeResolver.Instance, ContractlessStandardResolverAllowPrivate.Instance); 13 | MessagePackSerializer.SetDefaultResolver(ContractlessStandardResolverAllowPrivate.Instance); 14 | } 15 | 16 | public byte[] Serialize(TData data) 17 | { 18 | return MessagePackSerializer.Typeless.Serialize(data); 19 | } 20 | 21 | public object Deserialize(byte[] data, Type type) 22 | { 23 | return data == null || data.Length == 0 ? null : MessagePackSerializer.Typeless.Deserialize(data); 24 | } 25 | 26 | public T Deserialize(byte[] data) 27 | { 28 | return data == null || data.Length == 0 ? default : (T)MessagePackSerializer.Typeless.Deserialize(data); 29 | } 30 | 31 | public string ToJson(TData data) 32 | { 33 | return data == null ? default : MessagePackSerializer.ToJson(data); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Uragano.Codec.MessagePack/SerializerHelper.cs: -------------------------------------------------------------------------------- 1 | using MP = MessagePack; 2 | using MessagePack.Resolvers; 3 | 4 | namespace Uragano.Codec.MessagePack 5 | { 6 | public class SerializerHelper 7 | { 8 | static SerializerHelper() 9 | { 10 | CompositeResolver.RegisterAndSetAsDefault(NativeDateTimeResolver.Instance, ContractlessStandardResolverAllowPrivate.Instance); 11 | MP.MessagePackSerializer.SetDefaultResolver(ContractlessStandardResolverAllowPrivate.Instance); 12 | } 13 | 14 | public static byte[] Serialize(T data) 15 | { 16 | return MP.MessagePackSerializer.Typeless.Serialize(data); 17 | } 18 | 19 | public static object Deserialize(byte[] data) 20 | { 21 | return data == null || data.Length==0 ? null : MP.MessagePackSerializer.Typeless.Deserialize(data); 22 | } 23 | 24 | public static T Deserialize(byte[] data) 25 | { 26 | return data == null || data.Length == 0 ? default : (T)Deserialize(data); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Uragano.Codec.MessagePack/Uragano.Codec.MessagePack.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | 0.0.4 8 | A simple, high performance RPC library. 9 | https://github.com/1100100/Uragano 10 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 11 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 12 | 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Uragano.Consul/CommonMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace Uragano.Consul 6 | { 7 | internal class CommonMethods 8 | { 9 | internal static ConsulClientConfigure ReadConsulClientConfigure(IConfigurationSection configurationSection) 10 | { 11 | var client = new ConsulClientConfigure(); 12 | if (configurationSection.Exists()) 13 | { 14 | var addressSection = configurationSection.GetSection("address"); 15 | if (addressSection.Exists()) 16 | client.Address = new Uri(addressSection.Value); 17 | var tokenSection = configurationSection.GetSection("token"); 18 | if (tokenSection.Exists()) 19 | client.Token = tokenSection.Value; 20 | var dcSection = configurationSection.GetSection("datacenter"); 21 | if (dcSection.Exists()) 22 | client.Datacenter = dcSection.Value; 23 | client.WaitTime = string.IsNullOrWhiteSpace(configurationSection.GetValue("timeout")) 24 | ? default 25 | : TimeSpan.FromSeconds(configurationSection.GetValue("timeout")); 26 | } 27 | return client; 28 | } 29 | 30 | internal static ConsulRegisterServiceConfiguration ReadRegisterServiceConfiguration(IConfigurationSection configurationSection) 31 | { 32 | var service = new ConsulRegisterServiceConfiguration(); 33 | 34 | var idSection = configurationSection.GetSection("id"); 35 | if (idSection.Exists()) 36 | service.Id = idSection.Value; 37 | var nameSection = configurationSection.GetSection("name"); 38 | if (nameSection.Exists()) 39 | service.Name = nameSection.Value; 40 | var hcSection = configurationSection.GetSection("HealthCheckInterval"); 41 | if (hcSection.Exists()) 42 | service.HealthCheckInterval = 43 | TimeSpan.FromSeconds(configurationSection.GetValue("HealthCheckInterval")); 44 | 45 | service.EnableTagOverride = configurationSection.GetValue("EnableTagOverride"); 46 | service.Meta = configurationSection.GetValue>("meta"); 47 | service.Tags = configurationSection.GetValue("tags"); 48 | return service; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Uragano.Consul/ConsulClientConfigure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Consul; 3 | using Uragano.Abstractions; 4 | using Uragano.Abstractions.ServiceDiscovery; 5 | 6 | namespace Uragano.Consul 7 | { 8 | public class ConsulClientConfigure : ConsulClientConfiguration, IServiceDiscoveryClientConfiguration 9 | { 10 | public ConsulClientConfigure() 11 | { 12 | Address = new Uri(EnvironmentVariableReader.Get(EnvironmentVariables.uragano_consul_addr, "http://127.0.0.1:8500")); 13 | Token = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_consul_token); 14 | Datacenter = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_consul_dc, "dc1"); 15 | WaitTime = TimeSpan.FromSeconds(EnvironmentVariableReader.Get(EnvironmentVariables.uragano_consul_timeout, 10)); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Uragano.Consul/ConsulRegisterServiceConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Uragano.Abstractions; 4 | using Uragano.Abstractions.ServiceDiscovery; 5 | 6 | namespace Uragano.Consul 7 | { 8 | public class ConsulRegisterServiceConfiguration : IServiceRegisterConfiguration 9 | { 10 | public string Id { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_service_id); 11 | 12 | public string Name { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_service_name); 13 | 14 | public bool EnableTagOverride { get; set; } 15 | 16 | public Dictionary Meta { get; set; } 17 | 18 | public string[] Tags { get; set; } 19 | 20 | /// 21 | /// The default is 10 seconds 22 | /// 23 | public TimeSpan HealthCheckInterval { get; set; } = TimeSpan.FromSeconds(EnvironmentVariableReader.Get(EnvironmentVariables.uragano_consul_hc_interval, 10)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Uragano.Consul/ServiceStatusManageService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | using Uragano.Abstractions; 6 | using Uragano.Abstractions.ServiceDiscovery; 7 | 8 | namespace Uragano.Consul 9 | { 10 | public class ServiceStatusManageService : BackgroundService 11 | { 12 | private IServiceDiscovery ServiceDiscovery { get; } 13 | private static System.Timers.Timer Timer { get; set; } 14 | 15 | private ILogger Logger { get; } 16 | 17 | public ServiceStatusManageService(IServiceDiscovery serviceDiscovery, ILogger logger) 18 | { 19 | ServiceDiscovery = serviceDiscovery; 20 | Logger = logger; 21 | } 22 | 23 | 24 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 25 | { 26 | if (UraganoOptions.Consul_Node_Status_Refresh_Interval.Value.Ticks > 0) 27 | { 28 | Timer = new System.Timers.Timer(UraganoOptions.Consul_Node_Status_Refresh_Interval.Value.TotalMilliseconds); 29 | Timer.Elapsed += async (sender, args) => 30 | { 31 | if (stoppingToken.IsCancellationRequested) 32 | return; 33 | await ServiceDiscovery.NodeMonitor(stoppingToken); 34 | }; 35 | Timer.Enabled = true; 36 | } 37 | 38 | await Task.CompletedTask; 39 | } 40 | 41 | //public async Task StartAsync(CancellationToken cancellationToken) 42 | //{ 43 | // if (UraganoOptions.Client_Node_Status_Refresh_Interval.Value.Ticks > 0) 44 | // { 45 | // Timer = new System.Timers.Timer(UraganoOptions.Client_Node_Status_Refresh_Interval.Value.TotalMilliseconds); 46 | // Timer.Elapsed += async (sender, args) => 47 | // { 48 | // await ServiceStatusManageFactory.Refresh(cancellationToken); 49 | // }; 50 | // Timer.Enabled = true; 51 | // //NOTE:Replace with Timer 52 | // //Task.Factory.StartNew(async () => 53 | // //{ 54 | // // while (!CancellationTokenSource.IsCancellationRequested) 55 | // // { 56 | // // await ServiceStatusManageFactory.Refresh(CancellationTokenSource.Token); 57 | // // if (CancellationTokenSource.IsCancellationRequested) 58 | // // break; 59 | // // await Task.Delay(UraganoOptions.Client_Node_Status_Refresh_Interval.Value, 60 | // // CancellationTokenSource.Token); 61 | // // } 62 | 63 | // // Logger.LogTrace("Stop refreshing service status."); 64 | // //}, CancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); 65 | 66 | // } 67 | 68 | // await Task.CompletedTask; 69 | //} 70 | 71 | 72 | public override async Task StopAsync(CancellationToken cancellationToken) 73 | { 74 | Logger.LogInformation("Stop refreshing service status."); 75 | await base.StopAsync(cancellationToken); 76 | if (Timer == null) 77 | return; 78 | Timer.Enabled = false; 79 | Timer.Dispose(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Uragano.Consul/Uragano.Consul.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 7.1 6 | false 7 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 8 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 9 | https://github.com/1100100/Uragano 10 | A simple, high performance RPC library. 11 | 0.0.4 12 | 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Uragano.Consul/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Uragano.Abstractions; 3 | 4 | namespace Uragano.Consul 5 | { 6 | public static class UraganoBuilderExtensions 7 | { 8 | public static void AddConsul(this IUraganoBuilder builder, ConsulClientConfigure consulClientConfiguration) 9 | { 10 | builder.AddHostedService(); 11 | builder.AddServiceDiscovery(consulClientConfiguration); 12 | } 13 | 14 | public static void AddConsul(this IUraganoBuilder builder, IConfigurationSection clientConfigurationSection) 15 | { 16 | builder.AddConsul(CommonMethods.ReadConsulClientConfigure(clientConfigurationSection)); 17 | } 18 | 19 | public static void AddConsul(this IUraganoBuilder builder, ConsulClientConfigure consulClientConfiguration, ConsulRegisterServiceConfiguration consulAgentServiceConfiguration) 20 | { 21 | builder.AddHostedService(); 22 | builder.AddServiceDiscovery(consulClientConfiguration, consulAgentServiceConfiguration); 23 | } 24 | 25 | public static void AddConsul(this IUraganoBuilder builder, IConfigurationSection clientConfigurationSection, 26 | IConfigurationSection serviceConfigurationSection) 27 | { 28 | var service = CommonMethods.ReadRegisterServiceConfiguration(serviceConfigurationSection); 29 | var client = CommonMethods.ReadConsulClientConfigure(clientConfigurationSection); 30 | builder.AddConsul(client, service); 31 | } 32 | 33 | public static void AddConsul(this IUraganoSampleBuilder builder) 34 | { 35 | var client = builder.Configuration.GetSection("Uragano:ServiceDiscovery:Consul:Client"); 36 | var service = builder.Configuration.GetSection("Uragano:ServiceDiscovery:Consul:Service"); 37 | if (service.Exists()) 38 | builder.AddConsul(client, service); 39 | else 40 | builder.AddConsul(client); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Uragano.Core/HostedService/BootstrapStartup.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Uragano.Abstractions; 5 | using Uragano.Remoting; 6 | 7 | namespace Uragano.Core.HostedService 8 | { 9 | public class BootstrapStartup : IHostedService 10 | { 11 | private UraganoSettings UraganoSettings { get; } 12 | private IBootstrap Bootstrap { get; } 13 | 14 | public BootstrapStartup(UraganoSettings uraganoSettings, IBootstrap bootstrap) 15 | { 16 | UraganoSettings = uraganoSettings; 17 | Bootstrap = bootstrap; 18 | } 19 | 20 | public async Task StartAsync(CancellationToken cancellationToken) 21 | { 22 | if (UraganoSettings.ServerSettings == null) return; 23 | await Bootstrap.StartAsync(); 24 | } 25 | 26 | public async Task StopAsync(CancellationToken cancellationToken) 27 | { 28 | await Bootstrap.StopAsync(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Uragano.Core/HostedService/InfrastructureStartup.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | using Uragano.Abstractions; 6 | 7 | namespace Uragano.Core.HostedService 8 | { 9 | public class InfrastructureStartup : IHostedService 10 | { 11 | private UraganoSettings UraganoSettings { get; } 12 | private ILoggerFactory LoggerFactory { get; } 13 | 14 | 15 | public InfrastructureStartup(UraganoSettings uraganoSettings, ILoggerFactory loggerFactory) 16 | { 17 | UraganoSettings = uraganoSettings; 18 | LoggerFactory = loggerFactory; 19 | } 20 | 21 | public async Task StartAsync(CancellationToken cancellationToken) 22 | { 23 | ThreadPool.SetMinThreads(UraganoOptions.ThreadPool_MinThreads.Value, UraganoOptions.ThreadPool_CompletionPortThreads.Value); 24 | foreach (var provider in UraganoSettings.LoggerProviders) 25 | { 26 | LoggerFactory.AddProvider(provider); 27 | } 28 | 29 | await Task.CompletedTask; 30 | } 31 | 32 | public async Task StopAsync(CancellationToken cancellationToken) 33 | { 34 | await Task.CompletedTask; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Uragano.Core/HostedService/RemotingClientStartup.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Uragano.Remoting; 5 | 6 | namespace Uragano.Core.HostedService 7 | { 8 | public class RemotingClientStartup : IHostedService 9 | { 10 | private IClientFactory ClientFactory { get; } 11 | 12 | public RemotingClientStartup(IClientFactory clientFactory) 13 | { 14 | ClientFactory = clientFactory; 15 | } 16 | 17 | public async Task StartAsync(CancellationToken cancellationToken) 18 | { 19 | await Task.CompletedTask; 20 | } 21 | 22 | public async Task StopAsync(CancellationToken cancellationToken) 23 | { 24 | await ClientFactory.RemoveAllClient(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Uragano.Core/HostedService/ServiceDiscoveryStartup.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Uragano.Abstractions; 5 | using Uragano.Abstractions.ServiceDiscovery; 6 | 7 | namespace Uragano.Core.HostedService 8 | { 9 | public class ServiceDiscoveryStartup : IHostedService 10 | { 11 | private IServiceDiscovery ServiceDiscovery { get; } 12 | 13 | private ServerSettings ServerSettings { get; } 14 | 15 | public ServiceDiscoveryStartup(IServiceDiscovery serviceDiscovery, UraganoSettings uraganoSettings) 16 | { 17 | ServiceDiscovery = serviceDiscovery; 18 | ServerSettings = uraganoSettings.ServerSettings; 19 | } 20 | 21 | public async Task StartAsync(CancellationToken cancellationToken) 22 | { 23 | if (ServerSettings == null) 24 | return; 25 | await ServiceDiscovery.RegisterAsync(cancellationToken); 26 | } 27 | 28 | public async Task StopAsync(CancellationToken cancellationToken) 29 | { 30 | if (ServerSettings == null) 31 | return; 32 | await ServiceDiscovery.DeregisterAsync(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Uragano.Core/ScriptInjection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading.Tasks; 4 | using Uragano.Abstractions.CircuitBreaker; 5 | using Microsoft.CodeAnalysis.CSharp.Scripting; 6 | using Microsoft.CodeAnalysis.Scripting; 7 | 8 | namespace Uragano.Core 9 | { 10 | public class ScriptInjection : IScriptInjection 11 | { 12 | private static readonly ConcurrentDictionary ServiceCommand = 13 | new ConcurrentDictionary(); 14 | 15 | private static readonly ConcurrentDictionary ScriptResult = new ConcurrentDictionary(); 16 | 17 | public bool AddScript(string route, string script, string[] usingNamespaces = default) 18 | { 19 | return ServiceCommand.TryAdd(route, new ScriptDescriptor 20 | { 21 | Script = script, 22 | UsingNamespaces = usingNamespaces 23 | }); 24 | } 25 | 26 | public ScriptDescriptor GetScript(string route) 27 | { 28 | if (ServiceCommand.TryGetValue(route, out var value)) 29 | return value; 30 | throw new InvalidOperationException($"No script found for route {route}"); 31 | } 32 | 33 | public async Task Run(string route) 34 | { 35 | if (ScriptResult.TryGetValue(route, out var value)) 36 | return value; 37 | 38 | var script = GetScript(route); 39 | var scriptOptions = ScriptOptions.Default.WithImports("System.Threading.Tasks"); 40 | if (script.UsingNamespaces != null && script.UsingNamespaces.Length > 0) 41 | { 42 | scriptOptions = scriptOptions.WithReferences(script.UsingNamespaces); 43 | scriptOptions = scriptOptions.AddImports(script.UsingNamespaces); 44 | } 45 | var result = await CSharpScript.EvaluateAsync(script.Script, scriptOptions); 46 | ScriptResult.TryAdd(route, result); 47 | return result; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Uragano.Core/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Uragano.Abstractions; 6 | using Uragano.Abstractions.CircuitBreaker; 7 | using Uragano.Abstractions.Service; 8 | using Uragano.Codec.MessagePack; 9 | using Uragano.DynamicProxy; 10 | 11 | namespace Uragano.Core 12 | { 13 | public static class ServiceCollectionExtensions 14 | { 15 | public static IServiceCollection AddUragano(this IServiceCollection serviceCollection, Action builder) 16 | { 17 | serviceCollection.AddBase(); 18 | var config = new UraganoBuilder(serviceCollection); 19 | builder(config); 20 | serviceCollection.AddSingleton(config.UraganoSettings); 21 | return serviceCollection; 22 | } 23 | 24 | public static IServiceCollection AddUragano(this IServiceCollection serviceCollection, 25 | IConfiguration configuration, Action builder) 26 | { 27 | serviceCollection.AddBase(); 28 | var config = new UraganoSampleBuilder(serviceCollection, configuration); 29 | builder(config); 30 | serviceCollection.AddSingleton(config.UraganoSettings); 31 | return serviceCollection; 32 | } 33 | 34 | private static void AddBase(this IServiceCollection serviceCollection) 35 | { 36 | serviceCollection.AddSingleton(); 37 | serviceCollection.AddSingleton(); 38 | serviceCollection.AddSingleton(); 39 | serviceCollection.AddSingleton(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Uragano.Core/ServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Uragano.Abstractions; 4 | using Uragano.DynamicProxy; 5 | 6 | namespace Uragano.Core 7 | { 8 | public static class ServiceExtensions 9 | { 10 | 11 | public static TService SetMeta(this TService service, Dictionary meta) where TService : IService 12 | { 13 | if (service is DynamicProxyAbstract dynamicProxyAbstract) 14 | { 15 | foreach (var item in meta) 16 | { 17 | dynamicProxyAbstract.SetMeta(item.Key, item.Value); 18 | } 19 | } 20 | return service; 21 | } 22 | 23 | public static TService SetMeta(this TService service, params (string key, string value)[] meta) where TService : IService 24 | { 25 | 26 | return service.SetMeta(meta.ToDictionary(key => key.key, value => value.value)); 27 | } 28 | 29 | public static TService SetMeta(this TService service, string key, string value) where TService : IService 30 | { 31 | if (service is DynamicProxyAbstract dynamicProxyAbstract) 32 | { 33 | dynamicProxyAbstract.SetMeta(key, value); 34 | } 35 | return service; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Uragano.Core/Uragano.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 7 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 8 | https://github.com/1100100/Uragano 9 | A simple, high performance RPC library. 10 | 0.0.4 11 | 12 | false 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/DynamicProxyAbstract.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | 5 | namespace Uragano.DynamicProxy 6 | { 7 | public abstract class DynamicProxyAbstract 8 | { 9 | private Dictionary Meta { get; set; } 10 | 11 | private IRemotingInvoke RemotingInvoke { get; } 12 | 13 | protected DynamicProxyAbstract(IRemotingInvoke remotingInvoke) 14 | { 15 | RemotingInvoke = remotingInvoke; 16 | } 17 | 18 | public void SetMeta(string key, string value) 19 | { 20 | if (Meta == null) 21 | Meta = new Dictionary(); 22 | Meta.Add(key, value); 23 | } 24 | 25 | 26 | //protected void Invoke(object[] args, string route, string serviceName) 27 | //{ 28 | // RemotingInvoke.InvokeAsync(args, route, serviceName, Meta).ConfigureAwait(false).GetAwaiter().GetResult(); 29 | //} 30 | 31 | //protected T Invoke(object[] args, string route, string serviceName) 32 | //{ 33 | // return RemotingInvoke.InvokeAsync(args, route, serviceName, Meta).ConfigureAwait(false).GetAwaiter().GetResult(); 34 | //} 35 | 36 | 37 | protected async Task InvokeAsync(object[] args, string route, string serviceName) 38 | { 39 | await RemotingInvoke.InvokeAsync(args, route, serviceName, Meta); 40 | Meta?.Clear(); 41 | } 42 | 43 | protected async Task InvokeAsync(object[] args, string route, string serviceName) 44 | { 45 | var result = await RemotingInvoke.InvokeAsync(args, route, serviceName, Meta); 46 | Meta?.Clear(); 47 | return result; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/CachingDefaultInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | using Uragano.Abstractions.Service; 5 | 6 | namespace Uragano.DynamicProxy.Interceptor 7 | { 8 | public sealed class CachingDefaultInterceptor : InterceptorAbstract 9 | { 10 | private ICaching Caching { get; } 11 | private ICachingKeyGenerator KeyGenerator { get; } 12 | private ICachingOptions CachingOptions { get; } 13 | private IServiceFactory ServiceFactory { get; } 14 | 15 | 16 | 17 | public CachingDefaultInterceptor(ICaching caching, ICachingKeyGenerator keyGenerator, UraganoSettings uraganoSettings, IServiceFactory serviceFactory) 18 | { 19 | Caching = caching; 20 | KeyGenerator = keyGenerator; 21 | CachingOptions = uraganoSettings.CachingOptions; 22 | ServiceFactory = serviceFactory; 23 | } 24 | 25 | public override async Task Intercept(IInterceptorContext context) 26 | { 27 | var service = ServiceFactory.Get(context.ServiceRoute); 28 | if (service.CachingConfig == null) return await context.Next(); 29 | var key = KeyGenerator.ReplacePlaceholder(service.CachingConfig.KeyPlaceholder, service.CachingConfig.CustomKey, 30 | context.Args); 31 | if (!(context is InterceptorContext ctx)) 32 | throw new ArgumentNullException(); 33 | var (value, hasKey) = await Caching.Get(key, ctx.ReturnType); 34 | if (hasKey) 35 | return new ServiceResult(value); 36 | var result = await context.Next(); 37 | if (result.Status != RemotingStatus.Ok) 38 | return result; 39 | await Caching.Set(key, result.Result, service.CachingConfig.ExpireSeconds); 40 | return result; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/ClientDefaultInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Uragano.Abstractions; 3 | using Uragano.Abstractions.Exceptions; 4 | using Uragano.Remoting; 5 | using Uragano.Abstractions.CircuitBreaker; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace Uragano.DynamicProxy.Interceptor 10 | { 11 | public sealed class ClientDefaultInterceptor : InterceptorAbstract 12 | { 13 | private ILoadBalancing LoadBalancing { get; } 14 | private IClientFactory ClientFactory { get; } 15 | private ICircuitBreaker CircuitBreaker { get; } 16 | private UraganoSettings UraganoSettings { get; } 17 | 18 | public ClientDefaultInterceptor(ILoadBalancing loadBalancing, IClientFactory clientFactory, ICircuitBreaker circuitBreaker, UraganoSettings uraganoSettings) 19 | { 20 | LoadBalancing = loadBalancing; 21 | ClientFactory = clientFactory; 22 | CircuitBreaker = circuitBreaker; 23 | UraganoSettings = uraganoSettings; 24 | } 25 | 26 | public override async Task Intercept(IInterceptorContext context) 27 | { 28 | if (!(context is InterceptorContext ctx)) throw new ArgumentNullException(nameof(context)); 29 | //No circuit breaker 30 | if (UraganoSettings.CircuitBreakerOptions == null) 31 | { 32 | return await Exec(ctx.ServiceName, ctx.ServiceRoute, ctx.Args, ctx.Meta); 33 | } 34 | //Circuit breaker 35 | return await CircuitBreaker.ExecuteAsync(ctx.ServiceRoute, 36 | async () => await Exec(ctx.ServiceName, ctx.ServiceRoute, ctx.Args, ctx.Meta), ctx.ReturnType); 37 | } 38 | 39 | private async Task Exec(string serviceName, string route, object[] args, Dictionary meta) 40 | { 41 | var node = await LoadBalancing.GetNextNode(serviceName, route, args, meta); 42 | var client = await ClientFactory.CreateClientAsync(serviceName, node); 43 | var result = await client.SendAsync(new InvokeMessage(route, args, meta)); 44 | if (result.Status != RemotingStatus.Ok) 45 | throw new RemoteInvokeException(route, result.Result?.ToString(), result.Status); 46 | return result; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/InterceptorAbstract.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Uragano.Abstractions; 3 | 4 | 5 | namespace Uragano.DynamicProxy.Interceptor 6 | { 7 | public abstract class InterceptorAbstract : IInterceptor 8 | { 9 | public abstract Task Intercept(IInterceptorContext context); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/InterceptorAttributeAbstract.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | 5 | namespace Uragano.DynamicProxy.Interceptor 6 | { 7 | [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)] 8 | public abstract class InterceptorAttributeAbstract : Attribute, IInterceptor 9 | { 10 | 11 | public abstract Task Intercept(IInterceptorContext context); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/InterceptorContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Uragano.Abstractions; 7 | 8 | 9 | namespace Uragano.DynamicProxy.Interceptor 10 | { 11 | public class InterceptorContext : IInterceptorContext 12 | { 13 | public string ServiceRoute { get; internal set; } 14 | 15 | public Dictionary Meta { get; internal set; } 16 | 17 | public object[] Args { get; internal set; } 18 | 19 | public IServiceProvider ServiceProvider { get; internal set; } 20 | 21 | public MethodInfo MethodInfo { get; internal set; } 22 | 23 | public Type ReturnType { get; internal set; } 24 | 25 | public string ServiceName { get; internal set; } 26 | 27 | public Stack Interceptors { get; } = new Stack(); 28 | 29 | public async Task Next() 30 | { 31 | var interceptor = (IInterceptor)ServiceProvider.GetRequiredService(Interceptors.Pop()); 32 | return await interceptor.Intercept(this); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Interceptor/ServerDefaultInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Uragano.Abstractions; 4 | using Uragano.Abstractions.Service; 5 | 6 | namespace Uragano.DynamicProxy.Interceptor 7 | { 8 | public sealed class ServerDefaultInterceptor : InterceptorAbstract 9 | { 10 | private IServiceFactory ServiceFactory { get; } 11 | 12 | public ServerDefaultInterceptor(IServiceFactory serviceFactory) 13 | { 14 | ServiceFactory = serviceFactory; 15 | } 16 | 17 | public override async Task Intercept(IInterceptorContext context) 18 | { 19 | var service = ServiceFactory.Get(context.ServiceRoute); 20 | var instance = context.ServiceProvider.GetRequiredService(service.ServerMethodInfo.DeclaringType); 21 | return new ServiceResult(await service.MethodInvoker.InvokeAsync(instance, context.Args)); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/MethodInvoker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using Uragano.Abstractions.Service; 7 | 8 | namespace Uragano.DynamicProxy 9 | { 10 | public class MethodInvoker : IMethodInvoker 11 | { 12 | private MethodInfo MethodInfo { get; } 13 | 14 | private Func Invoker { get; } 15 | 16 | public MethodInvoker(MethodInfo methodInfo) 17 | { 18 | MethodInfo = methodInfo; 19 | Invoker = BuildInvoker(methodInfo); 20 | } 21 | 22 | public async Task InvokeAsync(object instance, params object[] args) 23 | { 24 | if (MethodInfo.ReturnType == typeof(Task)) 25 | { 26 | await Invoker(instance, args); 27 | return null; 28 | } 29 | return await Invoker(instance, args); 30 | } 31 | 32 | private Func BuildInvoker(MethodInfo methodInfo) 33 | { 34 | if (methodInfo == null) 35 | throw new ArgumentNullException(nameof(methodInfo), "MethodInfo cannot be null."); 36 | var instanceParameter = Expression.Parameter(typeof(object)); 37 | var argsParameter = Expression.Parameter(typeof(object[])); 38 | 39 | var argsExpressions = methodInfo.GetParameters().Select((item, index) => Expression.Convert(Expression.ArrayIndex(argsParameter, Expression.Constant(index)), item.ParameterType)); 40 | 41 | var instanceObj = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.DeclaringType ?? throw new InvalidOperationException()); 42 | var methodCaller = Expression.Call(instanceObj, methodInfo, argsExpressions); 43 | if (methodCaller.Type == typeof(Task)) 44 | { 45 | var action = Expression.Lambda>(methodCaller, instanceParameter, argsParameter).Compile(); 46 | return (instance, args) => { action(instance, args); return Task.CompletedTask; }; 47 | } 48 | 49 | var instanceMethodCaller = Expression.Convert(methodCaller, methodInfo.ReturnType); 50 | return Expression.Lambda>(instanceMethodCaller, instanceParameter, argsParameter).Compile(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/ReflectHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.Extensions.DependencyModel; 6 | 7 | namespace Uragano.DynamicProxy 8 | { 9 | public class ReflectHelper 10 | { 11 | private static readonly object LockObject = new object(); 12 | 13 | private static List Types { get; set; } 14 | 15 | private ReflectHelper() 16 | { 17 | } 18 | 19 | public static List GetDependencyTypes() 20 | { 21 | lock (LockObject) 22 | { 23 | if (Types != null) 24 | return Types; 25 | var ignoreAssemblyFix = new[] 26 | { 27 | "Microsoft", "System", "Consul", "Polly", "Newtonsoft.Json", "MessagePack", "Google.Protobuf","DotNetty","Exceptionless","CSRedis","SafeObjectPool", 28 | "Remotion.Linq", "SOS.NETCore", "WindowsBase", "mscorlib", "netstandard", "Uragano.Abstractions","Uragano.Core","Uragano.DynamicProxy","Uragano.Logging.Exceptionless","Uragano.Remoting","Uragano.Consul","Uragano.Codec.MessagePack","Uragano.Logging.Log4Net","Uragano.Logging.NLog","Uragano.Caching.Redis","Uragano.Caching.Memory" 29 | }; 30 | 31 | var assemblies = DependencyContext.Default.RuntimeLibraries.SelectMany(i => 32 | i.GetDefaultAssemblyNames(DependencyContext.Default) 33 | .Where(p => !ignoreAssemblyFix.Any(ignore => 34 | p.Name.StartsWith(ignore, StringComparison.CurrentCultureIgnoreCase))) 35 | .Select(z => Assembly.Load(new AssemblyName(z.Name)))).Where(p => !p.IsDynamic).ToList(); 36 | 37 | Types = assemblies.SelectMany(p => p.GetExportedTypes()).ToList(); 38 | return Types; 39 | } 40 | } 41 | 42 | public static Type Find(string typeFullName) 43 | { 44 | return Types.FirstOrDefault(p => p.FullName == typeFullName); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/RemotingInvoke.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Uragano.Abstractions; 7 | using Uragano.Abstractions.Exceptions; 8 | using Uragano.Abstractions.Service; 9 | using Uragano.DynamicProxy.Interceptor; 10 | 11 | namespace Uragano.DynamicProxy 12 | { 13 | public class RemotingInvoke : IRemotingInvoke 14 | { 15 | private IServiceFactory ServiceFactory { get; } 16 | private UraganoSettings UraganoSettings { get; } 17 | private IServiceProvider ServiceProvider { get; } 18 | 19 | public RemotingInvoke(IServiceFactory serviceFactory, UraganoSettings uraganoSettings, IServiceProvider serviceProvider) 20 | { 21 | ServiceFactory = serviceFactory; 22 | UraganoSettings = uraganoSettings; 23 | ServiceProvider = serviceProvider; 24 | } 25 | 26 | public async Task InvokeAsync(object[] args, string route, string serviceName, Dictionary meta = default) 27 | { 28 | var service = ServiceFactory.Get(route); 29 | 30 | using (var scope = ServiceProvider.CreateScope()) 31 | { 32 | var context = new InterceptorContext 33 | { 34 | ServiceProvider = scope.ServiceProvider, 35 | Args = args, 36 | ServiceRoute = route, 37 | Meta = meta, 38 | MethodInfo = service.ClientMethodInfo, 39 | ReturnType = typeof(T), 40 | ServiceName = serviceName 41 | }; 42 | 43 | context.Interceptors.Push(typeof(ClientDefaultInterceptor)); 44 | if (service.CachingConfig != null) 45 | context.Interceptors.Push(typeof(CachingDefaultInterceptor)); 46 | foreach (var interceptor in service.ClientInterceptors) 47 | { 48 | context.Interceptors.Push(interceptor); 49 | } 50 | 51 | var result = await ((IInterceptor)scope.ServiceProvider.GetRequiredService(context.Interceptors.Pop())).Intercept(context); 52 | if (result.Status != RemotingStatus.Ok) 53 | throw new RemoteInvokeException(route, result.Result?.ToString(), result.Status); 54 | 55 | return result.Result == null ? default : (T)result.Result; 56 | } 57 | } 58 | 59 | public async Task InvokeAsync(object[] args, string route, string serviceName, Dictionary meta = default) 60 | { 61 | var service = ServiceFactory.Get(route); 62 | 63 | using (var scope = ServiceProvider.CreateScope()) 64 | { 65 | var context = new InterceptorContext 66 | { 67 | ServiceProvider = scope.ServiceProvider, 68 | Args = args, 69 | ServiceRoute = route, 70 | Meta = meta, 71 | MethodInfo = service.ClientMethodInfo, 72 | ServiceName = serviceName 73 | }; 74 | 75 | context.Interceptors.Push(typeof(ClientDefaultInterceptor)); 76 | foreach (var interceptor in service.ClientInterceptors) 77 | { 78 | context.Interceptors.Push(interceptor); 79 | } 80 | 81 | if (UraganoSettings.ClientGlobalInterceptors.Any()) 82 | { 83 | foreach (var interceptor in UraganoSettings.ClientGlobalInterceptors) 84 | { 85 | context.Interceptors.Push(interceptor); 86 | } 87 | } 88 | 89 | await ((IInterceptor)scope.ServiceProvider.GetRequiredService(context.Interceptors.Pop())).Intercept(context); 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Uragano.DynamicProxy/Uragano.DynamicProxy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 8 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 9 | https://github.com/1100100/Uragano 10 | A simple, high performance RPC library. 11 | 0.0.4 12 | 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Exceptionless/Uragano.Logging.Exceptionless.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | false 6 | 0.0.4 7 | Owen 8 | Owen 9 | A simple, high performance RPC library. 10 | 11 | https://github.com/1100100/Uragano 12 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 13 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 14 | MIT 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Exceptionless/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Exceptionless; 3 | using Exceptionless.Extensions.Logging; 4 | using Exceptionless.Storage; 5 | using Microsoft.Extensions.Configuration; 6 | using Uragano.Abstractions; 7 | 8 | namespace Uragano.Logging.Exceptionless 9 | { 10 | public static class UraganoBuilderExtensions 11 | { 12 | public static void AddExceptionlessLogger(this IUraganoBuilder builder, string apiKey, string serverUrl = "") 13 | { 14 | builder.AddLogger(new ExceptionlessLoggerProvider(ExceptionlessClient.Default)); 15 | 16 | ExceptionlessClient.Default.Configuration.ApiKey = apiKey; 17 | if (!string.IsNullOrWhiteSpace(serverUrl)) 18 | ExceptionlessClient.Default.Configuration.ConfigServerUrl = serverUrl; 19 | } 20 | 21 | public static void AddExceptionlessLogger(this IUraganoBuilder builder, Action configure) 22 | { 23 | builder.AddLogger(new ExceptionlessLoggerProvider(configure)); 24 | } 25 | 26 | public static void AddExceptionlessLogger(this IUraganoBuilder builder, IConfiguration configuration) 27 | { 28 | ExceptionlessClient.Default.Configuration.ReadFromConfiguration(configuration); 29 | builder.AddLogger(new ExceptionlessLoggerProvider(ExceptionlessClient.Default)); 30 | } 31 | public static void AddExceptionlessLogger(this IUraganoSampleBuilder builder) 32 | { 33 | ExceptionlessClient.Default.Configuration.ReadFromConfiguration(builder.Configuration.GetSection("Uragano:Logging:Exceptionless")); 34 | builder.AddLogger(new ExceptionlessLoggerProvider(ExceptionlessClient.Default)); 35 | } 36 | 37 | private static void ReadFromConfiguration(this ExceptionlessConfiguration config, IConfiguration settings) 38 | { 39 | if (config == null) 40 | throw new ArgumentNullException(nameof(config)); 41 | 42 | if (settings == null) 43 | throw new ArgumentNullException(nameof(settings)); 44 | 45 | var apiKey = settings["ApiKey"]; 46 | if (!string.IsNullOrEmpty(apiKey) && apiKey != "API_KEY_HERE") 47 | config.ApiKey = apiKey; 48 | 49 | foreach (var data in settings.GetSection("DefaultData").GetChildren()) 50 | if (data.Value != null) 51 | config.DefaultData[data.Key] = data.Value; 52 | 53 | foreach (var tag in settings.GetSection("DefaultTags").GetChildren()) 54 | config.DefaultTags.Add(tag.Value); 55 | 56 | if (bool.TryParse(settings["Enabled"], out var enabled) && !enabled) 57 | config.Enabled = false; 58 | 59 | if (bool.TryParse(settings["IncludePrivateInformation"], out var includePrivateInformation) && !includePrivateInformation) 60 | config.IncludePrivateInformation = false; 61 | 62 | var serverUrl = settings["ServerUrl"]; 63 | if (!string.IsNullOrEmpty(serverUrl)) 64 | config.ServerUrl = serverUrl; 65 | 66 | var storagePath = settings["StoragePath"]; 67 | if (!string.IsNullOrEmpty(storagePath)) 68 | config.Resolver.Register(typeof(IObjectStorage), () => new FolderObjectStorage(config.Resolver, storagePath)); 69 | 70 | foreach (var setting in settings.GetSection("Settings").GetChildren()) 71 | if (setting.Value != null) 72 | config.Settings[setting.Key] = setting.Value; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Log4net/Log4NetLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Xml; 4 | using log4net; 5 | using log4net.Config; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Uragano.Logging.Log4Net 9 | { 10 | public class Log4NetLogger : ILogger 11 | { 12 | private readonly ILog Logger; 13 | 14 | public Log4NetLogger(string name, XmlElement config) 15 | { 16 | var repository = LogManager.CreateRepository( 17 | Assembly.GetEntryAssembly(), 18 | typeof(log4net.Repository.Hierarchy.Hierarchy) 19 | ); 20 | XmlConfigurator.Configure(repository, config); 21 | Logger = LogManager.GetLogger(repository.Name, name); 22 | } 23 | 24 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 25 | { 26 | if (!IsEnabled(logLevel)) 27 | return; 28 | if (formatter == null) 29 | { 30 | throw new ArgumentNullException(nameof(formatter)); 31 | } 32 | var message = formatter(state, exception); 33 | if (string.IsNullOrEmpty(message)) return; 34 | switch (logLevel) 35 | { 36 | case LogLevel.Critical: 37 | Logger.Fatal(message, exception); 38 | break; 39 | case LogLevel.Debug: 40 | case LogLevel.Trace: 41 | Logger.Debug(message, exception); 42 | break; 43 | case LogLevel.Error: 44 | Logger.Error(message, exception); 45 | break; 46 | case LogLevel.Information: 47 | Logger.Info(message, exception); 48 | break; 49 | case LogLevel.Warning: 50 | Logger.Warn(message, exception); 51 | break; 52 | default: 53 | Logger.Info(message, exception); 54 | break; 55 | } 56 | } 57 | 58 | public bool IsEnabled(LogLevel logLevel) 59 | { 60 | switch (logLevel) 61 | { 62 | case LogLevel.Critical: 63 | return Logger.IsFatalEnabled; 64 | case LogLevel.Debug: 65 | case LogLevel.Trace: 66 | return Logger.IsDebugEnabled; 67 | case LogLevel.Error: 68 | return Logger.IsErrorEnabled; 69 | case LogLevel.Information: 70 | return Logger.IsInfoEnabled; 71 | case LogLevel.Warning: 72 | return Logger.IsWarnEnabled; 73 | default: 74 | throw new ArgumentOutOfRangeException(nameof(logLevel)); 75 | } 76 | } 77 | 78 | public IDisposable BeginScope(TState state) 79 | { 80 | return null; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Log4net/Log4NetProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.IO; 3 | using System.Xml; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Uragano.Logging.Log4Net 7 | { 8 | public class Log4NetProvider : ILoggerProvider 9 | { 10 | private readonly ConcurrentDictionary _loggers = 11 | new ConcurrentDictionary(); 12 | 13 | private static XmlElement XmlElement { get; set; } 14 | 15 | private string ConfigXmlFile { get; } 16 | 17 | public Log4NetProvider(string configFilename) 18 | { 19 | ConfigXmlFile = configFilename; 20 | } 21 | 22 | public void Dispose() 23 | { 24 | _loggers.Clear(); 25 | } 26 | 27 | public ILogger CreateLogger(string categoryName) 28 | { 29 | return _loggers.GetOrAdd(categoryName, new Log4NetLogger(categoryName, ReadConfigFile(ConfigXmlFile))); 30 | } 31 | private static XmlElement ReadConfigFile(string filename) 32 | { 33 | if (XmlElement != null) 34 | return XmlElement; 35 | var log4NetConfig = new XmlDocument(); 36 | using (var stream = File.OpenRead(filename)) 37 | { 38 | log4NetConfig.Load(stream); 39 | return XmlElement = log4NetConfig["log4net"]; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Log4net/Uragano.Logging.Log4Net.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | false 6 | 0.0.4 7 | Owen 8 | Owen 9 | A simple, high performance RPC library. 10 | 11 | 12 | https://github.com/1100100/Uragano 13 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 14 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Uragano.Logging.Log4net/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Uragano.Abstractions; 2 | 3 | namespace Uragano.Logging.Log4Net 4 | { 5 | public static class UraganoBuilderExtensions 6 | { 7 | public static void AddLog4NetLogger(this IUraganoBuilder builder, string configXmlFile = "log4net.config") 8 | { 9 | builder.AddLogger(new Log4NetProvider(configXmlFile)); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Uragano.Logging.NLog/Uragano.Logging.NLog.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | 0.0.4 6 | Owen 7 | Owen 8 | A simple, high performance RPC library. 9 | 10 | https://github.com/1100100/Uragano 11 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 12 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 13 | false 14 | MIT 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Uragano.Logging.NLog/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Microsoft.Extensions.Configuration; 4 | using NLog; 5 | using NLog.Extensions.Logging; 6 | using Uragano.Abstractions; 7 | 8 | 9 | namespace Uragano.Logging.NLog 10 | { 11 | public static class UraganoBuilderExtensions 12 | { 13 | public static void AddNLogLogger(this IUraganoBuilder builder, string configXmlFile = "nlog.config") 14 | { 15 | LogManager.LoadConfiguration(Path.Combine(Directory.GetCurrentDirectory(), configXmlFile)); 16 | builder.AddLogger(new NLogLoggerProvider()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/IBootstrap.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Uragano.Remoting 4 | { 5 | public interface IBootstrap 6 | { 7 | 8 | Task StartAsync(); 9 | 10 | Task StopAsync(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/IClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions; 4 | 5 | namespace Uragano.Remoting 6 | { 7 | 8 | 9 | public interface IClient 10 | { 11 | Task SendAsync(IInvokeMessage message); 12 | 13 | Task DisconnectAsync(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/IClientFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Uragano.Abstractions.ServiceDiscovery; 4 | 5 | namespace Uragano.Remoting 6 | { 7 | public interface IClientFactory 8 | { 9 | Task CreateClientAsync(string serviceName, ServiceNodeInfo nodeInfo); 10 | 11 | Task RemoveClient(string host, int port); 12 | 13 | Task RemoveAllClient(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/IMessageListener.Default.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Uragano.Abstractions; 3 | 4 | namespace Uragano.Remoting 5 | { 6 | public class MessageListener : IMessageListener 7 | { 8 | public event ReceiveMessageHandler OnReceived; 9 | 10 | public async Task Received(TransportMessage message) 11 | { 12 | OnReceived?.Invoke(message); 13 | await Task.CompletedTask; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/IMessageListener.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Uragano.Abstractions; 3 | 4 | namespace Uragano.Remoting 5 | { 6 | public delegate void ReceiveMessageHandler(TransportMessage message); 7 | public interface IMessageListener 8 | { 9 | event ReceiveMessageHandler OnReceived; 10 | 11 | Task Received(TransportMessage message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.ConsistentHash.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Uragano.Abstractions; 8 | using Uragano.Abstractions.ConsistentHash; 9 | using Uragano.Abstractions.Exceptions; 10 | using Uragano.Abstractions.ServiceDiscovery; 11 | 12 | namespace Uragano.Remoting.LoadBalancing 13 | { 14 | public class LoadBalancingConsistentHash : ILoadBalancing 15 | { 16 | private static readonly object LockObject = new object(); 17 | 18 | private IServiceDiscovery ServiceDiscovery { get; } 19 | 20 | private ILogger Logger { get; } 21 | 22 | private static ConcurrentDictionary> ServicesInfo { get; } = new ConcurrentDictionary>(); 23 | 24 | public LoadBalancingConsistentHash(IServiceDiscovery serviceDiscovery,ILogger logger) 25 | { 26 | ServiceDiscovery = serviceDiscovery; 27 | Logger = logger; 28 | ServiceDiscovery.OnNodeJoin += OnNodeJoin; 29 | ServiceDiscovery.OnNodeLeave += OnNodeLeave; 30 | } 31 | 32 | 33 | private void OnNodeLeave(string serviceName, IReadOnlyList servicesId) 34 | { 35 | if (!servicesId.Any()) return; 36 | if (!ServicesInfo.TryGetValue(serviceName, out var service)) return; 37 | foreach (var node in servicesId) 38 | { 39 | service.RemoveNode(node); 40 | Logger.LogTrace($"Removed node {node}"); 41 | } 42 | } 43 | 44 | private void OnNodeJoin(string serviceName, IReadOnlyList nodes) 45 | { 46 | if (!nodes.Any()) 47 | return; 48 | if (!ServicesInfo.TryGetValue(serviceName, out var service)) return; 49 | foreach (var node in nodes) 50 | { 51 | service.AddNode(node, node.ServiceId); 52 | Logger.LogTrace($"Added node {node.ServiceId}"); 53 | } 54 | } 55 | 56 | public async Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, 57 | IReadOnlyDictionary serviceMeta) 58 | { 59 | var nodes = await ServiceDiscovery.GetServiceNodes(serviceName); 60 | if (!nodes.Any()) 61 | throw new NotFoundNodeException(serviceName); 62 | if (nodes.Count == 1) 63 | return nodes.First(); 64 | lock (LockObject) 65 | { 66 | if (serviceMeta == null || !serviceMeta.TryGetValue("x-consistent-hash-key", out var key) || string.IsNullOrWhiteSpace(key)) 67 | { 68 | throw new ArgumentNullException(nameof(serviceMeta), "Service metadata [x-consistent-hash-key] is null,Please call SetMeta method to pass in."); 69 | } 70 | 71 | var selectedNode= ServicesInfo.GetOrAdd(serviceName, k => 72 | { 73 | var consistentHash = new ConsistentHash(); 74 | foreach (var node in nodes) 75 | { 76 | consistentHash.AddNode(node, node.ServiceId); 77 | } 78 | ServicesInfo.TryAdd(serviceName, consistentHash); 79 | return consistentHash; 80 | }).GetNodeForKey(key); 81 | if(Logger.IsEnabled( LogLevel.Trace)) 82 | Logger.LogTrace($"Load to node {selectedNode.ServiceId}."); 83 | return selectedNode; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.Polling.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Uragano.Abstractions; 6 | using Uragano.Abstractions.Exceptions; 7 | using Uragano.Abstractions.ServiceDiscovery; 8 | 9 | namespace Uragano.Remoting.LoadBalancing 10 | { 11 | public class LoadBalancingPolling : ILoadBalancing 12 | { 13 | private IServiceDiscovery ServiceDiscovery { get; } 14 | 15 | private static int _index = -1; 16 | private static readonly object LockObject = new object(); 17 | 18 | private ILogger Logger { get; } 19 | public LoadBalancingPolling(IServiceDiscovery serviceDiscovery,ILogger logger) 20 | { 21 | ServiceDiscovery = serviceDiscovery; 22 | Logger = logger; 23 | } 24 | 25 | public async Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, IReadOnlyDictionary serviceMeta) 26 | { 27 | var nodes = await ServiceDiscovery.GetServiceNodes(serviceName); 28 | if (!nodes.Any()) 29 | throw new NotFoundNodeException(serviceName); 30 | if (nodes.Count == 1) 31 | return nodes.First(); 32 | lock (LockObject) 33 | { 34 | _index++; 35 | if (_index > nodes.Count - 1) 36 | _index = 0; 37 | if(Logger.IsEnabled( LogLevel.Trace)) 38 | Logger.LogTrace($"Load to node {nodes[_index].ServiceId}."); 39 | return nodes[_index]; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.Random.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Uragano.Abstractions; 7 | using Uragano.Abstractions.Exceptions; 8 | using Uragano.Abstractions.ServiceDiscovery; 9 | 10 | namespace Uragano.Remoting.LoadBalancing 11 | { 12 | public class LoadBalancingRandom : ILoadBalancing 13 | { 14 | private IServiceDiscovery ServiceDiscovery { get; } 15 | 16 | private ILogger Logger { get; } 17 | 18 | public LoadBalancingRandom(IServiceDiscovery serviceDiscovery,ILogger logger) 19 | { 20 | ServiceDiscovery = serviceDiscovery; 21 | Logger = logger; 22 | } 23 | public async Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, IReadOnlyDictionary serviceMeta) 24 | { 25 | var nodes = await ServiceDiscovery.GetServiceNodes(serviceName); 26 | if (!nodes.Any()) 27 | throw new NotFoundNodeException(serviceName); 28 | if (nodes.Count == 1) 29 | return nodes.First(); 30 | var node= nodes[new Random().Next(0, nodes.Count)]; 31 | if (Logger.IsEnabled(LogLevel.Trace)) 32 | Logger.LogTrace($"Load to node {node.ServiceId}."); 33 | return node; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.WeightedPolling.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Uragano.Abstractions; 7 | using Uragano.Abstractions.Exceptions; 8 | using Uragano.Abstractions.ServiceDiscovery; 9 | 10 | namespace Uragano.Remoting.LoadBalancing 11 | { 12 | public class LoadBalancingWeightedPolling : ILoadBalancing 13 | { 14 | private static readonly object LockObject = new object(); 15 | 16 | private IServiceDiscovery ServiceDiscovery { get; } 17 | 18 | private const string Key = "x-weighted-polling-current-value"; 19 | 20 | private ILogger Logger { get; } 21 | 22 | public LoadBalancingWeightedPolling(IServiceDiscovery serviceDiscovery,ILogger logger) 23 | { 24 | ServiceDiscovery = serviceDiscovery; 25 | Logger = logger; 26 | } 27 | public async Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, IReadOnlyDictionary serviceMeta) 28 | { 29 | var nodes = await ServiceDiscovery.GetServiceNodes(serviceName); 30 | if (!nodes.Any()) 31 | throw new NotFoundNodeException(serviceName); 32 | if (nodes.Count == 1) 33 | return nodes.First(); 34 | lock (LockObject) 35 | { 36 | 37 | var index = -1; 38 | var total = 0; 39 | for (var i = 0; i < nodes.Count; i++) 40 | { 41 | nodes[i].Attach.AddOrUpdate(Key, nodes[i].Weight, (key, old) => Convert.ToInt32(old) + nodes[i].Weight); 42 | total += nodes[i].Weight; 43 | if (index == -1 || GetCurrentWeightValue(nodes[index]) < GetCurrentWeightValue(nodes[i])) 44 | { 45 | index = i; 46 | } 47 | } 48 | nodes[index].Attach.AddOrUpdate(Key, -total, (k, old) => Convert.ToInt32(old) - total); 49 | var node= nodes[index]; 50 | if (Logger.IsEnabled(LogLevel.Trace)) 51 | Logger.LogTrace($"Load to node {node.ServiceId}."); 52 | return node; 53 | } 54 | } 55 | 56 | private static int GetCurrentWeightValue(ServiceNodeInfo node) 57 | { 58 | return !node.Attach.TryGetValue(Key, out var val) ? 0 : Convert.ToInt32(val); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.WeightedRandom.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Uragano.Abstractions; 7 | using Uragano.Abstractions.Exceptions; 8 | using Uragano.Abstractions.ServiceDiscovery; 9 | 10 | namespace Uragano.Remoting.LoadBalancing 11 | { 12 | public class LoadBalancingWeightedRandom : ILoadBalancing 13 | { 14 | private static readonly object LockObject = new object(); 15 | 16 | private IServiceDiscovery ServiceDiscovery { get; } 17 | 18 | private ILogger Logger { get; } 19 | 20 | public LoadBalancingWeightedRandom(IServiceDiscovery serviceDiscovery,ILogger logger) 21 | { 22 | ServiceDiscovery = serviceDiscovery; 23 | Logger = logger; 24 | } 25 | public async Task GetNextNode(string serviceName, string serviceRoute, IReadOnlyList serviceArgs, IReadOnlyDictionary serviceMeta) 26 | { 27 | var nodes = await ServiceDiscovery.GetServiceNodes(serviceName); 28 | if (!nodes.Any()) 29 | throw new NotFoundNodeException(serviceName); 30 | if (nodes.Count == 1) 31 | return nodes.First(); 32 | lock (LockObject) 33 | { 34 | var total = nodes.Sum(p => p.Weight); 35 | var offset = new Random().Next(0, total+1); 36 | var currentSum = 0; 37 | foreach (var node in nodes.OrderByDescending(p => p.Weight)) 38 | { 39 | currentSum += node.Weight; 40 | if (offset <= currentSum) 41 | { 42 | if (Logger.IsEnabled(LogLevel.Trace)) 43 | Logger.LogTrace($"Load to node {node.ServiceId}."); 44 | return node; 45 | } 46 | } 47 | var result= nodes[new Random().Next(0, nodes.Count)]; 48 | if (Logger.IsEnabled(LogLevel.Trace)) 49 | Logger.LogTrace($"Load to node {result.ServiceId}."); 50 | return result; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/LoadBalancing/LoadBalancing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Uragano.Remoting.LoadBalancing 4 | { 5 | public class LoadBalancing 6 | { 7 | private LoadBalancing() 8 | { 9 | } 10 | 11 | public static Type ConsistentHash { get; } = typeof(LoadBalancingConsistentHash); 12 | 13 | public static Type Polling { get; } = typeof(LoadBalancingPolling); 14 | 15 | public static Type WeightedPolling { get; } = typeof(LoadBalancingWeightedPolling); 16 | 17 | public static Type Random { get; } = typeof(LoadBalancingRandom); 18 | 19 | public static Type WeightedRandom { get; } = typeof(LoadBalancingWeightedRandom); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/MessageDecoder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using DotNetty.Buffers; 3 | using DotNetty.Codecs; 4 | using DotNetty.Transport.Channels; 5 | using Uragano.Abstractions; 6 | 7 | namespace Uragano.Remoting 8 | { 9 | public class MessageDecoder : MessageToMessageDecoder 10 | { 11 | private ICodec Codec { get; } 12 | 13 | 14 | public MessageDecoder(ICodec codec) 15 | { 16 | Codec = codec; 17 | } 18 | 19 | protected override void Decode(IChannelHandlerContext context, IByteBuffer message, List output) 20 | { 21 | var len = message.ReadableBytes; 22 | var array = new byte[len]; 23 | message.GetBytes(message.ReaderIndex, array, 0, len); 24 | //output.Add(SerializerHelper.Deserialize>(array)); 25 | output.Add(Codec.Deserialize(array, typeof(T))); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/MessageEncoder.cs: -------------------------------------------------------------------------------- 1 | using DotNetty.Buffers; 2 | using DotNetty.Codecs; 3 | using DotNetty.Transport.Channels; 4 | using Uragano.Abstractions; 5 | 6 | namespace Uragano.Remoting 7 | { 8 | public class MessageEncoder : MessageToByteEncoder> 9 | { 10 | private ICodec Codec { get; } 11 | 12 | public MessageEncoder(ICodec codec) 13 | { 14 | Codec = codec; 15 | } 16 | protected override void Encode(IChannelHandlerContext context, TransportMessage message, IByteBuffer output) 17 | { 18 | var r = output.WriteBytes(Codec.Serialize(message)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/ServerMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using DotNetty.Transport.Channels; 4 | using Microsoft.Extensions.Logging; 5 | using Uragano.Abstractions; 6 | using Uragano.Abstractions.Exceptions; 7 | using Uragano.Abstractions.Service; 8 | 9 | namespace Uragano.Remoting 10 | { 11 | public class ServerMessageHandler : ChannelHandlerAdapter 12 | { 13 | 14 | private IServiceFactory ServiceFactory { get; } 15 | 16 | private IServiceProvider ServiceProvider { get; } 17 | 18 | private ILogger Logger { get; } 19 | 20 | private ICodec Codec { get; } 21 | 22 | private ServerSettings ServerSettings { get; } 23 | 24 | public ServerMessageHandler(IServiceFactory serviceFactory, IServiceProvider serviceProvider, ILogger logger, ICodec codec, ServerSettings serverSettings) 25 | { 26 | ServiceFactory = serviceFactory; 27 | ServiceProvider = serviceProvider; 28 | Logger = logger; 29 | Codec = codec; 30 | ServerSettings = serverSettings; 31 | } 32 | 33 | public override void ChannelRead(IChannelHandlerContext context, object message) 34 | { 35 | Task.Run(async () => 36 | { 37 | var msg = message; 38 | if (!(msg is TransportMessage transportMessage)) 39 | throw new ArgumentNullException(nameof(message)); 40 | try 41 | { 42 | if (Logger.IsEnabled(LogLevel.Trace)) 43 | Logger.LogTrace($"The server received the message:\nCurrent node:{ServerSettings}\nRoute:{transportMessage.Body.Route}\nMessage id:{transportMessage.Id}\nArgs:{Codec.ToJson(transportMessage.Body.Args)}\nMeta:{Codec.ToJson(transportMessage.Body.Meta)}\n\n"); 44 | var result = await ServiceFactory.InvokeAsync(transportMessage.Body.Route, transportMessage.Body.Args, 45 | transportMessage.Body.Meta); 46 | await context.WriteAndFlushAsync(new TransportMessage 47 | { 48 | Id = transportMessage.Id, 49 | Body = result 50 | }); 51 | } 52 | catch (NotFoundRouteException e) 53 | { 54 | Logger.LogError(e, $"The server message processing failed:{e.Message}.\nCurrent node:{ServerSettings}\nRoute:{transportMessage.Body.Route}\nMessage id:{transportMessage.Id}\n\n"); 55 | await context.WriteAndFlushAsync(new TransportMessage 56 | { 57 | Id = transportMessage.Id, 58 | Body = new ServiceResult(e.Message, RemotingStatus.NotFound) 59 | }); 60 | } 61 | catch (Exception e) 62 | { 63 | Logger.LogError(e, $"The server message processing failed:{e.Message}.\nCurrent node:{ServerSettings}\nRoute:{transportMessage.Body.Route}\nMessage id:{transportMessage.Id}\n\n"); 64 | await context.WriteAndFlushAsync(new TransportMessage 65 | { 66 | Id = transportMessage.Id, 67 | Body = new ServiceResult(e.Message, RemotingStatus.Error) 68 | }); 69 | } 70 | }); 71 | } 72 | 73 | public override void ChannelReadComplete(IChannelHandlerContext context) 74 | { 75 | context.Flush(); 76 | } 77 | 78 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) 79 | { 80 | context.CloseAsync(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/TransportContext.cs: -------------------------------------------------------------------------------- 1 | namespace Uragano.Remoting 2 | { 3 | public class TransportContext 4 | { 5 | public string Host { get; set; } 6 | 7 | public int Port { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Uragano.Remoting/Uragano.Remoting.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | false 7 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 8 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 9 | https://github.com/1100100/Uragano 10 | A simple, high performance RPC library. 11 | 0.0.4 12 | 13 | Owen 14 | Owen 15 | MIT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/CommonMethods.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | 3 | namespace Uragano.ZooKeeper 4 | { 5 | internal class CommonMethods 6 | { 7 | internal static ZooKeeperClientConfigure ReadZooKeeperClientConfigure(IConfigurationSection configurationSection) 8 | { 9 | var client = new ZooKeeperClientConfigure(); 10 | if (configurationSection.Exists()) 11 | { 12 | var connection = configurationSection.GetSection("ConnectionString"); 13 | if (connection.Exists()) 14 | client.ConnectionString = connection.Value; 15 | var sessionTimeout = configurationSection.GetSection("SessionTimeout"); 16 | if (sessionTimeout.Exists()) 17 | client.SessionTimeout = int.Parse(sessionTimeout.Value); 18 | 19 | var canBeReadOnly = configurationSection.GetSection("CanBeReadOnly"); 20 | if (canBeReadOnly.Exists()) 21 | client.CanBeReadOnly = bool.Parse(canBeReadOnly.Value); 22 | } 23 | return client; 24 | } 25 | 26 | internal static ZooKeeperRegisterServiceConfiguration ReadRegisterServiceConfiguration(IConfigurationSection configurationSection) 27 | { 28 | var service = new ZooKeeperRegisterServiceConfiguration(); 29 | 30 | var idSection = configurationSection.GetSection("id"); 31 | if (idSection.Exists()) 32 | service.Id = idSection.Value; 33 | var nameSection = configurationSection.GetSection("name"); 34 | if (nameSection.Exists()) 35 | service.Name = nameSection.Value; 36 | //var hcSection = configurationSection.GetSection("HealthCheckInterval"); 37 | //if (hcSection.Exists()) 38 | // service.HealthCheckInterval = 39 | // TimeSpan.FromMilliseconds(configurationSection.GetValue("HealthCheckInterval")); 40 | 41 | //service.EnableTagOverride = configurationSection.GetValue("EnableTagOverride"); 42 | //service.Meta = configurationSection.GetValue>("meta"); 43 | //service.Tags = configurationSection.GetValue("tags"); 44 | return service; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/Uragano.ZooKeeper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | latest 6 | 0.0.4 7 | Owen 8 | Uragano.ZooKeeper 9 | A simple, high performance RPC library. 10 | https://github.com/1100100/Uragano 11 | https://raw.githubusercontent.com/1100100/Uragano/master/icon.png 12 | Uragano,RPC,DotNetty,Microservice,MessagePack,DynamicProxy,dotnetcore,service-discovery,polly,circuit-breaker,consul,zookeeper,dependency-injection 13 | false 14 | MIT 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/UraganoBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Uragano.Abstractions; 5 | 6 | namespace Uragano.ZooKeeper 7 | { 8 | public static class UraganoBuilderExtensions 9 | { 10 | public static void AddZooKeeper(this IUraganoBuilder builder, ZooKeeperClientConfigure zookeeperClientConfiguration) 11 | { 12 | builder.AddServiceDiscovery(zookeeperClientConfiguration); 13 | } 14 | 15 | public static void AddZooKeeper(this IUraganoBuilder builder, IConfigurationSection clientConfigurationSection) 16 | { 17 | builder.AddZooKeeper(CommonMethods.ReadZooKeeperClientConfigure(clientConfigurationSection)); 18 | } 19 | 20 | public static void AddZooKeeper(this IUraganoBuilder builder, ZooKeeperClientConfigure zookeeperClientConfiguration, ZooKeeperRegisterServiceConfiguration zookeeperAgentServiceConfiguration) 21 | { 22 | builder.AddServiceDiscovery(zookeeperClientConfiguration, zookeeperAgentServiceConfiguration); 23 | } 24 | 25 | public static void AddZooKeeper(this IUraganoBuilder builder, IConfigurationSection clientConfigurationSection, 26 | IConfigurationSection serviceConfigurationSection) 27 | { 28 | var service = CommonMethods.ReadRegisterServiceConfiguration(serviceConfigurationSection); 29 | var client = CommonMethods.ReadZooKeeperClientConfigure(clientConfigurationSection); 30 | builder.AddZooKeeper(client, service); 31 | } 32 | 33 | public static void AddZooKeeper(this IUraganoSampleBuilder builder) 34 | { 35 | var client = builder.Configuration.GetSection("Uragano:ServiceDiscovery:ZooKeeper:Client"); 36 | var service = builder.Configuration.GetSection("Uragano:ServiceDiscovery:ZooKeeper:Service"); 37 | if (service.Exists()) 38 | builder.AddZooKeeper(client, service); 39 | else 40 | builder.AddZooKeeper(client); 41 | } 42 | 43 | //private static void CreateZooKeeperClient(IUraganoBuilder builder, ZooKeeperClientConfigure zookeeperClientConfiguration) 44 | //{ 45 | // var client = new org.apache.zookeeper.ZooKeeper(zookeeperClientConfiguration.ConnectionString, zookeeperClientConfiguration.SessionTimeout, new UraganoWatcher(), zookeeperClientConfiguration.SessionId, string.IsNullOrWhiteSpace(zookeeperClientConfiguration.SessionPassword) ? null : Encoding.UTF8.GetBytes(zookeeperClientConfiguration.SessionPassword), zookeeperClientConfiguration.CanBeReadOnly); 46 | // builder.ServiceCollection.AddSingleton(client); 47 | //} 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/UraganoWatcher.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using org.apache.zookeeper; 3 | 4 | namespace Uragano.ZooKeeper 5 | { 6 | delegate Task ZooKeeperHandler(string path, Watcher.Event.KeeperState keeperState, Watcher.Event.EventType eventType); 7 | internal class UraganoWatcher : Watcher 8 | { 9 | public event ZooKeeperHandler OnChange; 10 | 11 | public override async Task process(WatchedEvent @event) 12 | { 13 | var state = @event.getState(); 14 | var path = @event.getPath(); 15 | var type = @event.get_Type(); 16 | OnChange?.Invoke(path, state, type); 17 | await Task.CompletedTask; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/ZooKeeperClientConfigure.cs: -------------------------------------------------------------------------------- 1 | using Uragano.Abstractions; 2 | using Uragano.Abstractions.ServiceDiscovery; 3 | 4 | namespace Uragano.ZooKeeper 5 | { 6 | public class ZooKeeperClientConfigure : IServiceDiscoveryClientConfiguration 7 | { 8 | /// 9 | /// comma separated host:port pairs, each corresponding to a zk server. 10 | /// 11 | public string ConnectionString { get; set; } = 12 | EnvironmentVariableReader.Get(EnvironmentVariables.uragano_zk_addr, "127.0.0.1:2181"); 13 | 14 | /// 15 | /// session timeout in milliseconds 16 | /// 17 | public int SessionTimeout { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_zk_session_timeout, 1000 * 10); 18 | 19 | 20 | /// 21 | /// (added in 3.4) whether the created client is allowed to go to read-only mode in case of 22 | /// partitioning. Read-only mode basically means that if the client can't find any majority servers but there's partitioned 23 | /// server it could reach, it connects to one in read-only mode, i.e. read requests are allowed while write requests are not. 24 | /// It continues seeking for majority in the background. 25 | /// 26 | public bool CanBeReadOnly { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_zk_readonly, false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Uragano.ZooKeeper/ZooKeeperRegisterServiceConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Uragano.Abstractions; 2 | using Uragano.Abstractions.ServiceDiscovery; 3 | 4 | namespace Uragano.ZooKeeper 5 | { 6 | public class ZooKeeperRegisterServiceConfiguration : IServiceRegisterConfiguration 7 | { 8 | public string Id { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_service_id); 9 | public string Name { get; set; } = EnvironmentVariableReader.Get(EnvironmentVariables.uragano_service_name); 10 | 11 | public override string ToString() 12 | { 13 | return $"/{Name}/{Id}"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/XUnitTest/CodecMessagePackTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Uragano.Codec.MessagePack; 3 | using Xunit; 4 | 5 | namespace XUnitTest 6 | { 7 | public class CodecMessagePackTest 8 | { 9 | 10 | [Theory] 11 | [InlineData(null)] 12 | [MemberData(nameof(GetEntity))] 13 | public void SerializeTest(TestCodecEntity obj) 14 | { 15 | var bytes = SerializerHelper.Serialize(obj); 16 | Assert.NotNull(bytes); 17 | var codec = new MessagePackCodec(); 18 | Assert.NotNull(codec.Serialize(obj)); 19 | } 20 | 21 | [Fact] 22 | public void DeserializeTest() 23 | { 24 | var entity = new TestCodecEntity { Id = 1, Name = "Jack" }; 25 | var bytes = SerializerHelper.Serialize(entity); 26 | Assert.Same(typeof(TestCodecEntity), SerializerHelper.Deserialize(bytes).GetType()); 27 | Assert.Same(typeof(TestCodecEntity), SerializerHelper.Deserialize(bytes).GetType()); 28 | 29 | Assert.Null(SerializerHelper.Deserialize(null)); 30 | Assert.Null(SerializerHelper.Deserialize(null)); 31 | 32 | var codec = new MessagePackCodec(); 33 | Assert.Same(typeof(TestCodecEntity), codec.Deserialize(bytes, typeof(TestCodecEntity)).GetType()); 34 | Assert.Same(typeof(TestCodecEntity), codec.Deserialize(bytes).GetType()); 35 | 36 | Assert.Null(codec.Deserialize(null, typeof(TestCodecEntity))); 37 | Assert.Null(codec.Deserialize(null)); 38 | } 39 | 40 | public static List GetEntity() 41 | { 42 | return new List { new object[] { new TestCodecEntity { Id = 1, Name = "Jack" } } }; 43 | } 44 | } 45 | 46 | public class TestCodecEntity 47 | { 48 | public int Id { get; set; } 49 | 50 | public string Name { get; set; } 51 | } 52 | } -------------------------------------------------------------------------------- /test/XUnitTest/ConsulTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Text; 6 | using Microsoft.Extensions.Logging; 7 | using Moq; 8 | using Uragano.Abstractions; 9 | using Uragano.Consul; 10 | using Xunit; 11 | using Xunit.Abstractions; 12 | 13 | namespace XUnitTest 14 | { 15 | [Collection("TestConsulCollection")] 16 | public class ConsulTest : ConsulFixture, IDisposable 17 | { 18 | private ConsulFixture ConsulFixture { get; } 19 | 20 | private ConsulServiceDiscovery ConsulServiceDiscovery { get; } 21 | 22 | private ITestOutputHelper Output { get; } 23 | 24 | public ConsulTest(ITestOutputHelper output, ConsulFixture consulFixture) 25 | { 26 | Output = output; 27 | 28 | ConsulFixture = consulFixture; 29 | var logger = Mock.Of>(); 30 | Output.WriteLine((logger != null).ToString()); 31 | //ConsulServiceDiscovery = new ConsulServiceDiscovery(consulFixture.UraganoSettings, logger,new ); 32 | } 33 | 34 | [Fact] 35 | public void RegisterAsync_Success_Test() 36 | { 37 | Assert.True(ConsulServiceDiscovery.RegisterAsync().GetAwaiter().GetResult()); 38 | } 39 | 40 | 41 | [Fact] 42 | public void RegisterAsync_Fail_Test() 43 | { 44 | Assert.Throws(() => 45 | { 46 | ConsulServiceDiscovery.RegisterAsync().GetAwaiter().GetResult(); 47 | }); 48 | } 49 | [Fact] 50 | public void QueryServiceAsync() 51 | { 52 | var result = ConsulServiceDiscovery 53 | .QueryServiceAsync( "XUnitTest1").GetAwaiter().GetResult(); 54 | Assert.True(result.Count >= 0); 55 | } 56 | 57 | public void Dispose() 58 | { 59 | ConsulServiceDiscovery.DeregisterAsync().GetAwaiter().GetResult(); 60 | } 61 | } 62 | 63 | 64 | 65 | public class ConsulFixture 66 | { 67 | public UraganoSettings UraganoSettings { get; } 68 | 69 | public ConsulFixture() 70 | { 71 | UraganoSettings = new UraganoSettings 72 | { 73 | //ServiceDiscoveryClientConfiguration = new ConsulClientConfigure 74 | //{ 75 | // Address = new Uri("http://192.168.1.254:8500"), 76 | // Token = "5ece74af-19d1-0e61-b25c-b9665d29f50b" 77 | //}, 78 | ServerSettings = new ServerSettings 79 | { 80 | Address = "127.0.0.1", 81 | Port = 1000 82 | } 83 | }; 84 | } 85 | 86 | } 87 | [CollectionDefinition("TestConsulCollection")] 88 | public class ConsulCollection : ICollectionFixture 89 | { 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/XUnitTest/DynamicProxy/MethodInvokerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Uragano.DynamicProxy; 6 | using Xunit; 7 | 8 | namespace XUnitTest.DynamicProxy 9 | { 10 | public class MethodInvokerTest 11 | { 12 | 13 | 14 | [Fact] 15 | public void ConstructMethodTest() 16 | { 17 | var method = typeof(MethodInvokerMethod).GetMethod("GetString"); 18 | Assert.Throws(() => 19 | { 20 | new MethodInvoker(null); 21 | }); 22 | var methodInvoker = new MethodInvoker(method); 23 | Assert.NotNull(methodInvoker); 24 | } 25 | 26 | [Fact] 27 | public void InvokerAsyncTest() 28 | { 29 | var type = typeof(MethodInvokerMethod); 30 | var method1 = type.GetMethod("GetString"); 31 | var methodInvoker1 = new MethodInvoker(method1); 32 | var result1 = methodInvoker1.InvokeAsync(new MethodInvokerMethod()).GetAwaiter().GetResult(); 33 | Assert.Equal("test string", result1); 34 | 35 | var method2 = type.GetMethod("Exec"); 36 | var methodInvoker2 = new MethodInvoker(method2); 37 | var result2 = methodInvoker2.InvokeAsync(new MethodInvokerMethod()).GetAwaiter().GetResult(); 38 | Assert.Null(result2); 39 | } 40 | } 41 | 42 | public class MethodInvokerMethod 43 | { 44 | public async Task GetString() 45 | { 46 | return await Task.FromResult("test string"); 47 | } 48 | 49 | public async Task Exec() 50 | { 51 | await Task.CompletedTask; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/XUnitTest/XUnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------