Skip to content

Commit

Permalink
Merge pull request #175 from Cysharp/client-filter
Browse files Browse the repository at this point in the history
Client Filter
  • Loading branch information
neuecc committed Aug 8, 2019
2 parents fe941f5 + 44b148d commit 63d3f94
Show file tree
Hide file tree
Showing 57 changed files with 2,111 additions and 1,953 deletions.
146 changes: 145 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,150 @@ Here is example of what kind of filter can be stacked.

GlobalFilter can attach to MagicOnionOptions.

ClientFilter
---
MagicOnion client-filter is powerful feature to hook before-after invoke. It is useful than gRPC client interceptor.

> Currently only suppots on Unary.
```csharp
// you can attach in MagicOnionClient.Create.
var client = MagicOnionClient.Create<ICalcService>(channel, new IClientFilter[]
{
new LoggingFilter(),
new AppendHeaderFilter(),
new RetryFilter()
});
```

You can create custom client-filter by implements `IClientFilter.SendAsync`.

```csharp
public class IDemoFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
try
{
/* Before Request, context.MethodPath/CallOptions/Items, etc */

var response = await next(context); /* Call next filter or method body */

/* After Request, response.GetStatus/GetTrailers/GetResponseAs<T>, etc */

return response;
}
catch (RpcException ex)
{
/* Get gRPC Error Response */
throw;
}
catch (OperationCanceledException ex)
{
/* If canceled */
throw;
}
catch (Exception ex)
{
/* Other Exception */
throw;
}
finally
{
/* Common Finalize */
}
}
}
```

Here is the sample filters, you can imagine what you can do.

```csharp
public class AppendHeaderFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
// add the common header(like authentcation).
var header = context.CallOptions.Headers;
header.Add("x-foo", "abcdefg");
header.Add("x-bar", "hijklmn");

return await next(context);
}
}

public class LoggingFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
Console.WriteLine("Request Begin:" + context.MethodPath); // Debug.Log in Unity.
var sw = Stopwatch.StartNew();
var response = await next(context);
sw.Stop();

Console.WriteLine("Request Completed:" + context.MethodPath + ", Elapsed:" + sw.Elapsed.TotalMilliseconds + "ms");

return response;
}
}

public class ResponseHandlingFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
var response = await next(context);

if (context.MethodPath == "ICalc/Sum")
{
// You can cast response type.
var sumResult = await response.GetResponseAs<int>();
Console.WriteLine("Called Sum, Result:" + sumResult);
}

return response;
}
}

public class MockRequestFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
if (context.MethodPath == "ICalc/Sum")
{
// don't call next, return mock result.
return new ResponseContext<int>(9999);
}

return await next(context);
}
}

public class RetryFilter : IClientFilter
{
public async ValueTask<ResponseContext> SendAsync(RequestContext context, Func<RequestContext, ValueTask<ResponseContext>> next)
{
Exception lastException = null;
var retryCount = 0;
while (retryCount != 3)
{
try
{
// using same CallOptions so be careful to add duplicate headers or etc.
return await next(context);
}
catch (Exception ex)
{
lastException = ex;
}
retryCount++;
}

throw new Exception("Retry failed", lastException);
}
}
```

ServiceContext and Lifecycle
---
Service/StreamingHub's method or `MagicOnionFilter` can access `this.Context` it is
Expand Down Expand Up @@ -374,7 +518,7 @@ gRPC In(

StreamingHub instance is shared while connecting so StreamingHub's field can use cache area of connection.

MagicOnionOption/Loggin
MagicOnionOption/Logging
---
`MagicOnionOption` can pass to `MagicOnionEngine.BuildServerServiceDefinition(MagicOnionOptions option)`.

Expand Down
37 changes: 37 additions & 0 deletions sandbox/DynamicCodeDumper/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,49 @@ public interface ITestHub : IStreamingHub<ITestHub, IMessageReceiver>
Task<double> RetrunMoreArgument(int x, string y, double z);
}

public interface ITestService : IService<ITestService>
{
UnaryResult<int> Sum(int x, int y);
Task<UnaryResult<int>> Sum2(int x, int y);


UnaryResult<MyResponse> Unary1(int x, int y, string z = "unknown");
UnaryResult<MyResponse> Unary2(MyRequest req);
UnaryResult<MyResponse> Unary3();
UnaryResult<Nil> Unary4();
UnaryResult<MyStructResponse> Unary5(MyStructRequest req);
}

public class MyRequest
{
}

public class MyResponse
{
}
public struct MyStructRequest
{
}

public struct MyStructResponse
{
}
public struct Nil
{
}

class Program
{
static void Main(string[] args)
{
//var _ = DynamicBroadcasterBuilder<IMessageReceiver>.BroadcasterType;
//var a = MagicOnion.Server.Hubs.AssemblyHolder.Save();

// var _ = DynamicClientBuilder<ITestService>.ClientType;
//var c = MagicOnion.Client.DynamicClientAssemblyHolder.Save();
//Verify(c);

//var _ = MagicOnionClient.Create<ITestHub>((Channel)null, null);

//var __ = StreamingHubClientBuilder<ITestHub, IMessageReceiver>.ClientType;
//var b = MagicOnion.Client.StreamingHubClientAssemblyHolder.Save();
Expand Down
34 changes: 20 additions & 14 deletions src/MagicOnion.Client.Unity/Assembly-CSharp-Editor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@
<ItemGroup>
<Compile Include="Assets\Scripts\Editor\PackageExporter.cs" />
<Reference Include="Unity.TextMeshPro.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.PackageManagerUI.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.PackageManagerUI.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.PackageManagerUI.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.CollabProxy.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.CollabProxy.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.CollabProxy.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.TextMeshPro">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.DataPrivacy">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.Analytics.DataPrivacy.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.Analytics.DataPrivacy.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AIModule">
<HintPath>C:/Program Files/Unity/Hub/Editor/2018.3.3f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll</HintPath>
Expand Down Expand Up @@ -311,31 +311,37 @@
<HintPath>C:/Program Files (x86)/Microsoft Visual Studio Tools for Unity/16.0/Editor/SyntaxTree.VisualStudio.Unity.Bridge.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Google.Protobuf/lib/net45/Google.Protobuf.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Google.Protobuf/lib/net45/Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core/lib/net45/Grpc.Core.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core/lib/net45/Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core.Api">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.dll</HintPath>
</Reference>
<Reference Include="System.Interactive.Async">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/System.Interactive.Async/lib/net45/System.Interactive.Async.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/System.Interactive.Async/lib/net45/System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.Advertisements">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.ads@2.0.8/Editor/UnityEditor.Advertisements.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.ads@2.0.8/Editor/UnityEditor.Advertisements.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.StandardEvents">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.StandardEvents.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.StandardEvents.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.Tracker">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Tracker.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Tracker.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.Purchasing">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.purchasing@2.0.3/Editor/UnityEditor.Purchasing.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.purchasing@2.0.3/Editor/UnityEditor.Purchasing.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions">
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Scripts/NetStandardLibraries/System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe">
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Scripts/NetStandardLibraries/System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="mscorlib">
<HintPath>C:/Program Files/Unity/Hub/Editor/2018.3.3f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/mscorlib.dll</HintPath>
Expand Down
37 changes: 20 additions & 17 deletions src/MagicOnion.Client.Unity/Assembly-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@
<Compile Include="Assets\Scripts\Loader.cs" />
<Compile Include="Assets\Scripts\MagicOnion\AsyncLock.cs" />
<Compile Include="Assets\Scripts\MagicOnion\AsyncStreamReaderExtensions.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\ClientFilter.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\DynamicClientBuilder.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\EmbeddedServices\HeartbeatClient.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\EmbeddedServices\PingClient.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\InterceptInvokeHelper.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\MagicOnionClient.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\MagicOnionClientBase.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Client\StreamingHubClient.cs" />
Expand All @@ -90,12 +92,7 @@
<Compile Include="Assets\Scripts\MagicOnion\Server\Hubs\MethodIdAttribute.cs" />
<Compile Include="Assets\Scripts\MagicOnion\ServerStreamingResult.cs" />
<Compile Include="Assets\Scripts\MagicOnion\UnaryResult.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\AsyncMethodBuilderAttribute.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\AsyncStreamReaderExtensions.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\ChannelExtensions.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\CompileStopperDuringPlayMode.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\EditorWindowSupportsCallInvoker.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\MagicOnionWindow.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\UnityDebugLogger.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Unity\UnsafeBlitResolver.cs" />
<Compile Include="Assets\Scripts\MagicOnion\Utils\AsyncLocalShim.cs" />
Expand Down Expand Up @@ -192,19 +189,19 @@
<Compile Include="Assets\Scripts\Tests\SimpleTest.cs" />
<Compile Include="Assets\Scripts\Tests\StandardTest.cs" />
<Reference Include="Unity.TextMeshPro.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.PackageManagerUI.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.PackageManagerUI.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.PackageManagerUI.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.CollabProxy.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.CollabProxy.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.CollabProxy.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.TextMeshPro">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.DataPrivacy">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.Analytics.DataPrivacy.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/ScriptAssemblies/Unity.Analytics.DataPrivacy.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AIModule">
<HintPath>C:/Program Files/Unity/Hub/Editor/2018.3.3f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll</HintPath>
Expand Down Expand Up @@ -408,25 +405,31 @@
<HintPath>C:/Program Files/Unity/Hub/Editor/2018.3.3f1/Editor/Data/UnityExtensions/Unity/UnitySpatialTracking/RuntimeEditor/UnityEngine.SpatialTracking.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Google.Protobuf/lib/net45/Google.Protobuf.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Google.Protobuf/lib/net45/Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core/lib/net45/Grpc.Core.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core/lib/net45/Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core.Api">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.dll</HintPath>
</Reference>
<Reference Include="System.Interactive.Async">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/System.Interactive.Async/lib/net45/System.Interactive.Async.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Plugins/System.Interactive.Async/lib/net45/System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.Editor">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Editor.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.StandardEvents">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.StandardEvents.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.StandardEvents.dll</HintPath>
</Reference>
<Reference Include="Unity.Analytics.Tracker">
<HintPath>C:/Git/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Tracker.dll</HintPath>
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Library/PackageCache/com.unity.analytics@3.2.2/Unity.Analytics.Tracker.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions">
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Scripts/NetStandardLibraries/System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe">
<HintPath>C:/GitHubRepositories/MagicOnion/src/MagicOnion.Client.Unity/Assets/Scripts/NetStandardLibraries/System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="mscorlib">
<HintPath>C:/Program Files/Unity/Hub/Editor/2018.3.3f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/mscorlib.dll</HintPath>
Expand Down
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 63d3f94

Please sign in to comment.