blob: 4bb06ed87fbf7c0f08d83fdce5b748d647e3acc2 [file] [log] [blame]
Jan Tattermuschc0b37212015-03-13 08:35:41 -07001#region Copyright notice and license
2
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003// Copyright 2015-2016 gRPC authors.
Jan Tattermuschc0b37212015-03-13 08:35:41 -07004//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005// 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 Tattermuschc0b37212015-03-13 08:35:41 -07008//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009// http://www.apache.org/licenses/LICENSE-2.0
Jan Tattermuschc0b37212015-03-13 08:35:41 -070010//
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011// 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 Tattermuschc0b37212015-03-13 08:35:41 -070016
17#endregion
18
Mehrdad Afsharib8e36242018-02-11 20:10:29 -080019using System;
20using Grpc.Core.Interceptors;
Jan Tattermusch054fae72016-03-23 07:54:50 -070021using Grpc.Core.Internal;
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070022using Grpc.Core.Utils;
Jan Tattermuschc0b37212015-03-13 08:35:41 -070023
24namespace Grpc.Core
25{
Jan Tattermusch9e144142015-08-17 14:58:09 -070026 /// <summary>
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070027 /// Generic base class for client-side stubs.
28 /// </summary>
29 public abstract class ClientBase<T> : ClientBase
Jan Tattermuschb2403582016-03-23 07:40:28 -070030 where T : ClientBase<T>
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070031 {
32 /// <summary>
Jan Tattermuschb2403582016-03-23 07:40:28 -070033 /// 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 Tattermuschd9495ab2016-03-22 15:01:57 -070043 /// Initializes a new instance of <c>ClientBase</c> class.
44 /// </summary>
Jan Tattermusch2f0a8372016-03-23 09:16:49 -070045 /// <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 Tattermuschd9495ab2016-03-22 15:01:57 -070053 /// <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 Tattermuschc831a442016-03-22 17:23:55 -070067 /// 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 Tattermusch2f0a8372016-03-23 09:16:49 -070074 var newConfiguration = this.Configuration.WithHost(host);
75 return NewInstance(newConfiguration);
Jan Tattermuschc831a442016-03-22 17:23:55 -070076 }
77
78 /// <summary>
Jan Tattermusch2f0a8372016-03-23 09:16:49 -070079 /// Creates a new instance of client from given <c>ClientBaseConfiguration</c>.
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070080 /// </summary>
Jan Tattermusch2f0a8372016-03-23 09:16:49 -070081 protected abstract T NewInstance(ClientBaseConfiguration configuration);
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070082 }
83
84 /// <summary>
Jan Tattermusche5c9b802015-07-14 17:46:58 -070085 /// Base class for client-side stubs.
Jan Tattermuschc0b37212015-03-13 08:35:41 -070086 /// </summary>
Jan Tattermusche5c9b802015-07-14 17:46:58 -070087 public abstract class ClientBase
Jan Tattermuschc0b37212015-03-13 08:35:41 -070088 {
Jan Tattermusch2f0a8372016-03-23 09:16:49 -070089 readonly ClientBaseConfiguration configuration;
Jan Tattermuschd9495ab2016-03-22 15:01:57 -070090 readonly CallInvoker callInvoker;
Jan Tattermuschc0b37212015-03-13 08:35:41 -070091
Jan Tattermusch12855fc2015-08-24 16:43:23 -070092 /// <summary>
Jan Tattermuschb2403582016-03-23 07:40:28 -070093 /// 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 Tattermusch12855fc2015-08-24 16:43:23 -0700103 /// Initializes a new instance of <c>ClientBase</c> class.
104 /// </summary>
Jan Tattermusch2f0a8372016-03-23 09:16:49 -0700105 /// <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 Tattermusch12855fc2015-08-24 16:43:23 -0700115 /// <param name="channel">The channel to use for remote call invocation.</param>
Jan Tattermuschd9495ab2016-03-22 15:01:57 -0700116 public ClientBase(Channel channel) : this(new DefaultCallInvoker(channel))
Jan Tattermuschc0b37212015-03-13 08:35:41 -0700117 {
Jan Tattermuschd9495ab2016-03-22 15:01:57 -0700118 }
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 Tattermusch2f0a8372016-03-23 09:16:49 -0700124 public ClientBase(CallInvoker callInvoker) : this(new ClientBaseConfiguration(callInvoker, null))
Jan Tattermuschd9495ab2016-03-22 15:01:57 -0700125 {
Jan Tattermuschd9495ab2016-03-22 15:01:57 -0700126 }
127
128 /// <summary>
129 /// Gets the call invoker.
130 /// </summary>
131 protected CallInvoker CallInvoker
132 {
133 get { return this.callInvoker; }
Jan Tattermuschc0b37212015-03-13 08:35:41 -0700134 }
Jan Tattermusch2f0a8372016-03-23 09:16:49 -0700135
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 Afshari4bc49f52018-02-11 23:19:34 -0800152 private class ClientHeaderInterceptor : GenericInterceptor
Mehrdad Afsharib8e36242018-02-11 20:10:29 -0800153 {
154 readonly Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor;
155
156 /// <summary>
157 /// Creates a new instance of ClientHeaderInterceptor given the specified header interceptor function.
158 /// </summary>
159 public ClientHeaderInterceptor(Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor)
160 {
161 this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, "interceptor");
162 }
163
Mehrdad Afsharic1c29e32018-02-21 11:55:22 -0800164 protected override ClientCallHooks<TRequest, TResponse> InterceptCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, bool clientStreaming, bool serverStreaming, TRequest request)
Mehrdad Afsharib8e36242018-02-11 20:10:29 -0800165 {
Mehrdad Afshari4bc49f52018-02-11 23:19:34 -0800166 var newHostAndCallOptions = interceptor(context.Method, context.Host, context.Options);
Mehrdad Afsharic1c29e32018-02-21 11:55:22 -0800167 return new ClientCallHooks<TRequest, TResponse>
Mehrdad Afshari4bc49f52018-02-11 23:19:34 -0800168 {
Mehrdad Afsharic1c29e32018-02-21 11:55:22 -0800169 ContextOverride = new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Item1, newHostAndCallOptions.Item2)
Mehrdad Afshari4bc49f52018-02-11 23:19:34 -0800170 };
Mehrdad Afsharib8e36242018-02-11 20:10:29 -0800171 }
172 }
173
Jan Tattermusch2f0a8372016-03-23 09:16:49 -0700174 readonly CallInvoker undecoratedCallInvoker;
175 readonly string host;
176
177 internal ClientBaseConfiguration(CallInvoker undecoratedCallInvoker, string host)
178 {
179 this.undecoratedCallInvoker = GrpcPreconditions.CheckNotNull(undecoratedCallInvoker);
180 this.host = host;
181 }
182
183 internal CallInvoker CreateDecoratedCallInvoker()
184 {
Mehrdad Afsharib8e36242018-02-11 20:10:29 -0800185 return undecoratedCallInvoker.Intercept(new ClientHeaderInterceptor((method, host, options) => Tuple.Create(this.host, options)));
Jan Tattermusch2f0a8372016-03-23 09:16:49 -0700186 }
187
188 internal ClientBaseConfiguration WithHost(string host)
189 {
190 GrpcPreconditions.CheckNotNull(host, "host");
191 return new ClientBaseConfiguration(this.undecoratedCallInvoker, host);
192 }
193 }
Jan Tattermuschc0b37212015-03-13 08:35:41 -0700194 }
195}