1 #region Copyright notice and license 2 3 // Copyright 2015 gRPC authors. 4 // 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 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 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. 16 17 #endregion 18 19 using System; 20 using System.Threading.Tasks; 21 using Grpc.Core.Internal; 22 23 namespace Grpc.Core 24 { 25 /// <summary> 26 /// Helper methods for generated clients to make RPC calls. 27 /// Most users will use this class only indirectly and will be 28 /// making calls using client object generated from protocol 29 /// buffer definition files. 30 /// </summary> 31 public static class Calls 32 { 33 /// <summary> 34 /// Invokes a simple remote call in a blocking fashion. 35 /// </summary> 36 /// <returns>The response.</returns> 37 /// <param name="call">The call definition.</param> 38 /// <param name="req">Request message.</param> 39 /// <typeparam name="TRequest">Type of request message.</typeparam> 40 /// <typeparam name="TResponse">The of response message.</typeparam> 41 public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) 42 where TRequest : class 43 where TResponse : class 44 { 45 var asyncCall = new AsyncCall<TRequest, TResponse>(call); 46 return asyncCall.UnaryCall(req); 47 } 48 49 /// <summary> 50 /// Invokes a simple remote call asynchronously. 51 /// </summary> 52 /// <returns>An awaitable call object providing access to the response.</returns> 53 /// <param name="call">The call definition.</param> 54 /// <param name="req">Request message.</param> 55 /// <typeparam name="TRequest">Type of request message.</typeparam> 56 /// <typeparam name="TResponse">The of response message.</typeparam> 57 public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) 58 where TRequest : class 59 where TResponse : class 60 { 61 var asyncCall = new AsyncCall<TRequest, TResponse>(call); 62 var asyncResult = asyncCall.UnaryCallAsync(req); 63 return new AsyncUnaryCall<TResponse>(asyncResult, 64 Callbacks<TRequest, TResponse>.GetHeaders, Callbacks<TRequest, TResponse>.GetStatus, 65 Callbacks<TRequest, TResponse>.GetTrailers, Callbacks<TRequest, TResponse>.Cancel, 66 asyncCall); 67 } 68 69 /// <summary> 70 /// Invokes a server streaming call asynchronously. 71 /// In server streaming scenario, client sends on request and server responds with a stream of responses. 72 /// </summary> 73 /// <returns>A call object providing access to the asynchronous response stream.</returns> 74 /// <param name="call">The call definition.</param> 75 /// <param name="req">Request message.</param> 76 /// <typeparam name="TRequest">Type of request message.</typeparam> 77 /// <typeparam name="TResponse">The of response messages.</typeparam> 78 public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) 79 where TRequest : class 80 where TResponse : class 81 { 82 var asyncCall = new AsyncCall<TRequest, TResponse>(call); asyncCall.StartServerStreamingCall(req)83 asyncCall.StartServerStreamingCall(req); 84 var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); 85 return new AsyncServerStreamingCall<TResponse>(responseStream, 86 Callbacks<TRequest, TResponse>.GetHeaders, Callbacks<TRequest, TResponse>.GetStatus, 87 Callbacks<TRequest, TResponse>.GetTrailers, Callbacks<TRequest, TResponse>.Cancel, 88 asyncCall); 89 } 90 91 /// <summary> 92 /// Invokes a client streaming call asynchronously. 93 /// In client streaming scenario, client sends a stream of requests and server responds with a single response. 94 /// </summary> 95 /// <param name="call">The call definition.</param> 96 /// <returns>An awaitable call object providing access to the response.</returns> 97 /// <typeparam name="TRequest">Type of request messages.</typeparam> 98 /// <typeparam name="TResponse">The of response message.</typeparam> 99 public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) 100 where TRequest : class 101 where TResponse : class 102 { 103 var asyncCall = new AsyncCall<TRequest, TResponse>(call); 104 var resultTask = asyncCall.ClientStreamingCallAsync(); 105 var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); 106 return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, 107 Callbacks<TRequest, TResponse>.GetHeaders, Callbacks<TRequest, TResponse>.GetStatus, 108 Callbacks<TRequest, TResponse>.GetTrailers, Callbacks<TRequest, TResponse>.Cancel, 109 asyncCall); 110 } 111 112 /// <summary> 113 /// Invokes a duplex streaming call asynchronously. 114 /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses. 115 /// The response stream is completely independent and both side can be sending messages at the same time. 116 /// </summary> 117 /// <returns>A call object providing access to the asynchronous request and response streams.</returns> 118 /// <param name="call">The call definition.</param> 119 /// <typeparam name="TRequest">Type of request messages.</typeparam> 120 /// <typeparam name="TResponse">Type of responsemessages.</typeparam> 121 public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) 122 where TRequest : class 123 where TResponse : class 124 { 125 var asyncCall = new AsyncCall<TRequest, TResponse>(call); asyncCall.StartDuplexStreamingCall()126 asyncCall.StartDuplexStreamingCall(); 127 var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); 128 var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); 129 return new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, 130 Callbacks<TRequest, TResponse>.GetHeaders, Callbacks<TRequest, TResponse>.GetStatus, 131 Callbacks<TRequest, TResponse>.GetTrailers, Callbacks<TRequest, TResponse>.Cancel, 132 asyncCall); 133 } 134 135 private static class Callbacks<TRequest, TResponse> 136 { 137 internal static readonly Func<object, Task<Metadata>> GetHeaders = state => ((AsyncCall<TRequest, TResponse>)state).ResponseHeadersAsync; 138 internal static readonly Func<object, Status> GetStatus = state => ((AsyncCall<TRequest, TResponse>)state).GetStatus(); 139 internal static readonly Func<object, Metadata> GetTrailers = state => ((AsyncCall<TRequest, TResponse>)state).GetTrailers(); 140 internal static readonly Action<object> Cancel = state => ((AsyncCall<TRequest, TResponse>)state).Cancel(); 141 } 142 } 143 } 144