Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 1 | #region Copyright notice and license |
| 2 | |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | // Copyright 2015-2016 gRPC authors. |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 4 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 5 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | // you may not use this file except in compliance with the License. |
| 7 | // You may obtain a copy of the License at |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 8 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | // http://www.apache.org/licenses/LICENSE-2.0 |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 10 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 11 | // Unless required by applicable law or agreed to in writing, software |
| 12 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | // See the License for the specific language governing permissions and |
| 15 | // limitations under the License. |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 16 | |
| 17 | #endregion |
| 18 | |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 19 | using System; |
| 20 | using Grpc.Core.Interceptors; |
Jan Tattermusch | 054fae7 | 2016-03-23 07:54:50 -0700 | [diff] [blame] | 21 | using Grpc.Core.Internal; |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 22 | using Grpc.Core.Utils; |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 23 | |
| 24 | namespace Grpc.Core |
| 25 | { |
Jan Tattermusch | 9e14414 | 2015-08-17 14:58:09 -0700 | [diff] [blame] | 26 | /// <summary> |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 27 | /// Generic base class for client-side stubs. |
| 28 | /// </summary> |
| 29 | public abstract class ClientBase<T> : ClientBase |
Jan Tattermusch | b240358 | 2016-03-23 07:40:28 -0700 | [diff] [blame] | 30 | where T : ClientBase<T> |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 31 | { |
| 32 | /// <summary> |
Jan Tattermusch | b240358 | 2016-03-23 07:40:28 -0700 | [diff] [blame] | 33 | /// Initializes a new instance of <c>ClientBase</c> class that |
| 34 | /// throws <c>NotImplementedException</c> upon invocation of any RPC. |
| 35 | /// This constructor is only provided to allow creation of test doubles |
| 36 | /// for client classes (e.g. mocking requires a parameterless constructor). |
| 37 | /// </summary> |
| 38 | protected ClientBase() : base() |
| 39 | { |
| 40 | } |
| 41 | |
| 42 | /// <summary> |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 43 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 44 | /// </summary> |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 45 | /// <param name="configuration">The configuration.</param> |
| 46 | protected ClientBase(ClientBaseConfiguration configuration) : base(configuration) |
| 47 | { |
| 48 | } |
| 49 | |
| 50 | /// <summary> |
| 51 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 52 | /// </summary> |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 53 | /// <param name="channel">The channel to use for remote call invocation.</param> |
| 54 | public ClientBase(Channel channel) : base(channel) |
| 55 | { |
| 56 | } |
| 57 | |
| 58 | /// <summary> |
| 59 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 60 | /// </summary> |
| 61 | /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param> |
| 62 | public ClientBase(CallInvoker callInvoker) : base(callInvoker) |
| 63 | { |
| 64 | } |
| 65 | |
| 66 | /// <summary> |
Jan Tattermusch | c831a44 | 2016-03-22 17:23:55 -0700 | [diff] [blame] | 67 | /// Creates a new client that sets host field for calls explicitly. |
| 68 | /// gRPC supports multiple "hosts" being served by a single server. |
| 69 | /// By default (if a client was not created by calling this method), |
| 70 | /// host <c>null</c> with the meaning "use default host" is used. |
| 71 | /// </summary> |
| 72 | public T WithHost(string host) |
| 73 | { |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 74 | var newConfiguration = this.Configuration.WithHost(host); |
| 75 | return NewInstance(newConfiguration); |
Jan Tattermusch | c831a44 | 2016-03-22 17:23:55 -0700 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | /// <summary> |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 79 | /// Creates a new instance of client from given <c>ClientBaseConfiguration</c>. |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 80 | /// </summary> |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 81 | protected abstract T NewInstance(ClientBaseConfiguration configuration); |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | /// <summary> |
Jan Tattermusch | e5c9b80 | 2015-07-14 17:46:58 -0700 | [diff] [blame] | 85 | /// Base class for client-side stubs. |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 86 | /// </summary> |
Jan Tattermusch | e5c9b80 | 2015-07-14 17:46:58 -0700 | [diff] [blame] | 87 | public abstract class ClientBase |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 88 | { |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 89 | readonly ClientBaseConfiguration configuration; |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 90 | readonly CallInvoker callInvoker; |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 91 | |
Jan Tattermusch | 12855fc | 2015-08-24 16:43:23 -0700 | [diff] [blame] | 92 | /// <summary> |
Jan Tattermusch | b240358 | 2016-03-23 07:40:28 -0700 | [diff] [blame] | 93 | /// Initializes a new instance of <c>ClientBase</c> class that |
| 94 | /// throws <c>NotImplementedException</c> upon invocation of any RPC. |
| 95 | /// This constructor is only provided to allow creation of test doubles |
| 96 | /// for client classes (e.g. mocking requires a parameterless constructor). |
| 97 | /// </summary> |
| 98 | protected ClientBase() : this(new UnimplementedCallInvoker()) |
| 99 | { |
| 100 | } |
| 101 | |
| 102 | /// <summary> |
Jan Tattermusch | 12855fc | 2015-08-24 16:43:23 -0700 | [diff] [blame] | 103 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 104 | /// </summary> |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 105 | /// <param name="configuration">The configuration.</param> |
| 106 | protected ClientBase(ClientBaseConfiguration configuration) |
| 107 | { |
| 108 | this.configuration = GrpcPreconditions.CheckNotNull(configuration, "configuration"); |
| 109 | this.callInvoker = configuration.CreateDecoratedCallInvoker(); |
| 110 | } |
| 111 | |
| 112 | /// <summary> |
| 113 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 114 | /// </summary> |
Jan Tattermusch | 12855fc | 2015-08-24 16:43:23 -0700 | [diff] [blame] | 115 | /// <param name="channel">The channel to use for remote call invocation.</param> |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 116 | public ClientBase(Channel channel) : this(new DefaultCallInvoker(channel)) |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 117 | { |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | /// <summary> |
| 121 | /// Initializes a new instance of <c>ClientBase</c> class. |
| 122 | /// </summary> |
| 123 | /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param> |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 124 | public ClientBase(CallInvoker callInvoker) : this(new ClientBaseConfiguration(callInvoker, null)) |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 125 | { |
Jan Tattermusch | d9495ab | 2016-03-22 15:01:57 -0700 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | /// <summary> |
| 129 | /// Gets the call invoker. |
| 130 | /// </summary> |
| 131 | protected CallInvoker CallInvoker |
| 132 | { |
| 133 | get { return this.callInvoker; } |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 134 | } |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 135 | |
| 136 | /// <summary> |
| 137 | /// Gets the configuration. |
| 138 | /// </summary> |
| 139 | internal ClientBaseConfiguration Configuration |
| 140 | { |
| 141 | get { return this.configuration; } |
| 142 | } |
| 143 | |
| 144 | /// <summary> |
| 145 | /// Represents configuration of ClientBase. The class itself is visible to |
| 146 | /// subclasses, but contents are marked as internal to make the instances opaque. |
| 147 | /// The verbose name of this class was chosen to make name clash in generated code |
| 148 | /// less likely. |
| 149 | /// </summary> |
| 150 | protected internal class ClientBaseConfiguration |
| 151 | { |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 152 | private class ClientBaseConfigurationInterceptor : Interceptor |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 153 | { |
| 154 | readonly Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor; |
| 155 | |
| 156 | /// <summary> |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 157 | /// Creates a new instance of ClientBaseConfigurationInterceptor given the specified header and host interceptor function. |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 158 | /// </summary> |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 159 | public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor) |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 160 | { |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 161 | this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor)); |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 162 | } |
| 163 | |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 164 | private ClientInterceptorContext<TRequest, TResponse> GetNewContext<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context) |
| 165 | where TRequest : class |
| 166 | where TResponse : class |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 167 | { |
Mehrdad Afshari | 4bc49f5 | 2018-02-11 23:19:34 -0800 | [diff] [blame] | 168 | var newHostAndCallOptions = interceptor(context.Method, context.Host, context.Options); |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 169 | return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Item1, newHostAndCallOptions.Item2); |
| 170 | } |
| 171 | |
| 172 | public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation) |
| 173 | { |
| 174 | return continuation(request, GetNewContext(context)); |
| 175 | } |
| 176 | |
| 177 | public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation) |
| 178 | { |
| 179 | return continuation(request, GetNewContext(context)); |
| 180 | } |
| 181 | |
| 182 | public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation) |
| 183 | { |
| 184 | return continuation(request, GetNewContext(context)); |
| 185 | } |
| 186 | |
| 187 | public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation) |
| 188 | { |
| 189 | return continuation(GetNewContext(context)); |
| 190 | } |
| 191 | |
| 192 | public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation) |
| 193 | { |
| 194 | return continuation(GetNewContext(context)); |
Mehrdad Afshari | b8e3624 | 2018-02-11 20:10:29 -0800 | [diff] [blame] | 195 | } |
| 196 | } |
| 197 | |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 198 | readonly CallInvoker undecoratedCallInvoker; |
| 199 | readonly string host; |
| 200 | |
| 201 | internal ClientBaseConfiguration(CallInvoker undecoratedCallInvoker, string host) |
| 202 | { |
| 203 | this.undecoratedCallInvoker = GrpcPreconditions.CheckNotNull(undecoratedCallInvoker); |
| 204 | this.host = host; |
| 205 | } |
| 206 | |
| 207 | internal CallInvoker CreateDecoratedCallInvoker() |
| 208 | { |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 209 | return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => Tuple.Create(this.host, options))); |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | internal ClientBaseConfiguration WithHost(string host) |
| 213 | { |
Mehrdad Afshari | a7c1b62 | 2018-02-22 07:52:48 -0800 | [diff] [blame] | 214 | GrpcPreconditions.CheckNotNull(host, nameof(host)); |
Jan Tattermusch | 2f0a837 | 2016-03-23 09:16:49 -0700 | [diff] [blame] | 215 | return new ClientBaseConfiguration(this.undecoratedCallInvoker, host); |
| 216 | } |
| 217 | } |
Jan Tattermusch | c0b3721 | 2015-03-13 08:35:41 -0700 | [diff] [blame] | 218 | } |
| 219 | } |