From cd918d99e8fa25f89b5b36e15e440e307c41fc7a Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Wed, 21 Feb 2018 10:32:01 -0800 Subject: [PATCH] Simplify service-side interceptor code --- .../ServerServiceDefinitionExtensions.cs | 82 +++++++++++++++++++ .../Grpc.Core/Internal/ServerCallHandler.cs | 25 +++--- .../Grpc.Core/ServerServiceDefinition.cs | 30 +------ 3 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs diff --git a/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs b/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs new file mode 100644 index 00000000000..21a07820374 --- /dev/null +++ b/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs @@ -0,0 +1,82 @@ +#region Copyright notice and license + +// Copyright 2018 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using System.Linq; +using Grpc.Core.Utils; + +namespace Grpc.Core.Interceptors +{ + /// + /// Extends the ServerServiceDefinition class to add methods used to register interceptors on the server side. + /// This is an EXPERIMENTAL API. + /// + public static class ServerServiceDefinitionExtensions + { + /// + /// Returns a instance that + /// intercepts incoming calls to the underlying service handler through the given interceptor. + /// This is an EXPERIMENTAL API. + /// + /// The instance to register interceptors on. + /// The interceptor to intercept the incoming invocations with. + /// + /// Multiple interceptors can be added on top of each other by calling + /// "serverServiceDefinition.Intercept(a, b, c)". The order of invocation will be "a", "b", and then "c". + /// Interceptors can be later added to an existing intercepted service definition, effectively + /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)". Note that + /// in this case, the last interceptor added will be the first to take control. + /// + public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, Interceptor interceptor) + { + GrpcPreconditions.CheckNotNull(serverServiceDefinition, "serverServiceDefinition"); + GrpcPreconditions.CheckNotNull(interceptor, "interceptor"); + return new ServerServiceDefinition(serverServiceDefinition.CallHandlers.ToDictionary(x => x.Key, x => x.Value.Intercept(interceptor))); + } + + /// + /// Returns a instance that + /// intercepts incoming calls to the underlying service handler through the given interceptors. + /// This is an EXPERIMENTAL API. + /// + /// The instance to register interceptors on. + /// + /// An array of interceptors to intercept the incoming invocations with. + /// Control is passed to the interceptors in the order specified. + /// + /// + /// Multiple interceptors can be added on top of each other by calling + /// "serverServiceDefinition.Intercept(a, b, c)". The order of invocation will be "a", "b", and then "c". + /// Interceptors can be later added to an existing intercepted service definition, effectively + /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)". Note that + /// in this case, the last interceptor added will be the first to take control. + /// + public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, params Interceptor[] interceptors) + { + GrpcPreconditions.CheckNotNull(serverServiceDefinition, "serverServiceDefinition"); + GrpcPreconditions.CheckNotNull(interceptors, "interceptors"); + + foreach (var interceptor in interceptors.Reverse()) + { + serverServiceDefinition = Intercept(serverServiceDefinition, interceptor); + } + + return serverServiceDefinition; + } + } +} \ No newline at end of file diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index f9bf40f2372..add72ad68da 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -31,14 +31,10 @@ namespace Grpc.Core.Internal internal interface IServerCallHandler { Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq); - } - - internal interface IInterceptableCallHandler - { IServerCallHandler Intercept(Interceptor interceptor); } - internal class UnaryServerCallHandler : IServerCallHandler, IInterceptableCallHandler + internal class UnaryServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { @@ -96,13 +92,13 @@ namespace Grpc.Core.Internal await finishedTask.ConfigureAwait(false); } - IServerCallHandler IInterceptableCallHandler.Intercept(Interceptor interceptor) + public IServerCallHandler Intercept(Interceptor interceptor) { return new UnaryServerCallHandler(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler)); } } - internal class ServerStreamingServerCallHandler : IServerCallHandler, IInterceptableCallHandler + internal class ServerStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { @@ -159,13 +155,13 @@ namespace Grpc.Core.Internal await finishedTask.ConfigureAwait(false); } - IServerCallHandler IInterceptableCallHandler.Intercept(Interceptor interceptor) + public IServerCallHandler Intercept(Interceptor interceptor) { return new ServerStreamingServerCallHandler(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler)); } } - internal class ClientStreamingServerCallHandler : IServerCallHandler, IInterceptableCallHandler + internal class ClientStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { @@ -222,13 +218,13 @@ namespace Grpc.Core.Internal await finishedTask.ConfigureAwait(false); } - IServerCallHandler IInterceptableCallHandler.Intercept(Interceptor interceptor) + public IServerCallHandler Intercept(Interceptor interceptor) { return new ClientStreamingServerCallHandler(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler)); } } - internal class DuplexStreamingServerCallHandler : IServerCallHandler, IInterceptableCallHandler + internal class DuplexStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { @@ -282,7 +278,7 @@ namespace Grpc.Core.Internal await finishedTask.ConfigureAwait(false); } - IServerCallHandler IInterceptableCallHandler.Intercept(Interceptor interceptor) + public IServerCallHandler Intercept(Interceptor interceptor) { return new DuplexStreamingServerCallHandler(method, (requestStream, responseStream, context) => interceptor.DuplexStreamingServerHandler(requestStream, responseStream, context, handler)); } @@ -314,6 +310,11 @@ namespace Grpc.Core.Internal { return callHandlerImpl.HandleCall(newRpc, cq); } + + public IServerCallHandler Intercept(Interceptor interceptor) + { + return this; // Do not intercept unimplemented services + } } internal static class HandlerUtils diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs index a42f543a5a7..07c6aa17967 100644 --- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs +++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs @@ -35,7 +35,7 @@ namespace Grpc.Core { readonly ReadOnlyDictionary callHandlers; - private ServerServiceDefinition(Dictionary callHandlers) + internal ServerServiceDefinition(Dictionary callHandlers) { this.callHandlers = new ReadOnlyDictionary(callHandlers); } @@ -48,34 +48,6 @@ namespace Grpc.Core } } - /// - /// Returns a instance that - /// intercepts calls to the underlying service handler via the given interceptor. - /// This is an EXPERIMENTAL API. - /// - /// The interceptor to register on service. - /// - /// Multiple interceptors can be added on top of each other by chaining them - /// like "service.Intercept(c).Intercept(b).Intercept(a)". Note that - /// in this case, the last interceptor added will be the first to take control, - /// i.e. "a" will run before "b" before "c". - /// - public ServerServiceDefinition Intercept(Interceptor interceptor) - { - GrpcPreconditions.CheckNotNull(interceptor, "interceptor"); - return new ServerServiceDefinition(CallHandlers.ToDictionary( - x => x.Key, x => - { - var value = x.Value; - var interceptable = value as IInterceptableCallHandler; - if (interceptable == null) - { - return value; - } - return interceptable.Intercept(interceptor); - })); - } - /// /// Creates a new builder object for ServerServiceDefinition. ///