diff options
author | Mehrdad Afshari <mehrdada@users.noreply.github.com> | 2018-02-21 10:32:01 -0800 |
---|---|---|
committer | Mehrdad Afshari <mmx@google.com> | 2018-02-21 18:30:19 -0800 |
commit | cd918d99e8fa25f89b5b36e15e440e307c41fc7a (patch) | |
tree | a3411c60680297d3a87b1c663151d6cf72c7e27c | |
parent | 89bdba9f8a46d350e1d7af882e8110cefc700360 (diff) |
Simplify service-side interceptor code
3 files changed, 96 insertions, 41 deletions
diff --git a/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs b/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs new file mode 100644 index 0000000000..21a0782037 --- /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 +{ + /// <summary> + /// Extends the ServerServiceDefinition class to add methods used to register interceptors on the server side. + /// This is an EXPERIMENTAL API. + /// </summary> + public static class ServerServiceDefinitionExtensions + { + /// <summary> + /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that + /// intercepts incoming calls to the underlying service handler through the given interceptor. + /// This is an EXPERIMENTAL API. + /// </summary> + /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param> + /// <param name="interceptor">The interceptor to intercept the incoming invocations with.</param> + /// <remarks> + /// 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. + /// </remarks> + 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))); + } + + /// <summary> + /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that + /// intercepts incoming calls to the underlying service handler through the given interceptors. + /// This is an EXPERIMENTAL API. + /// </summary> + /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param> + /// <param name="interceptors"> + /// An array of interceptors to intercept the incoming invocations with. + /// Control is passed to the interceptors in the order specified. + /// </param> + /// <remarks> + /// 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. + /// </remarks> + 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 f9bf40f237..add72ad68d 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<TRequest, TResponse> : IServerCallHandler, IInterceptableCallHandler + internal class UnaryServerCallHandler<TRequest, TResponse> : 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<TRequest, TResponse>(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler)); } } - internal class ServerStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler, IInterceptableCallHandler + internal class ServerStreamingServerCallHandler<TRequest, TResponse> : 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<TRequest, TResponse>(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler)); } } - internal class ClientStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler, IInterceptableCallHandler + internal class ClientStreamingServerCallHandler<TRequest, TResponse> : 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<TRequest, TResponse>(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler)); } } - internal class DuplexStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler, IInterceptableCallHandler + internal class DuplexStreamingServerCallHandler<TRequest, TResponse> : 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<TRequest, TResponse>(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 a42f543a5a..07c6aa1796 100644 --- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs +++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs @@ -35,7 +35,7 @@ namespace Grpc.Core { readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers; - private ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers) + internal ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers) { this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers); } @@ -49,34 +49,6 @@ namespace Grpc.Core } /// <summary> - /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that - /// intercepts calls to the underlying service handler via the given interceptor. - /// This is an EXPERIMENTAL API. - /// </summary> - /// <param name="interceptor">The interceptor to register on service.</param> - /// <remarks> - /// 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". - /// </remarks> - 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); - })); - } - - /// <summary> /// Creates a new builder object for <c>ServerServiceDefinition</c>. /// </summary> /// <returns>The builder object.</returns> |