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.Runtime.CompilerServices;
21 using System.Threading.Tasks;
22 
23 namespace Grpc.Core
24 {
25     /// <summary>
26     /// Return type for client streaming calls.
27     /// </summary>
28     /// <typeparam name="TRequest">Request message type for this call.</typeparam>
29     /// <typeparam name="TResponse">Response message type for this call.</typeparam>
30     public sealed class AsyncClientStreamingCall<TRequest, TResponse> : IDisposable
31     {
32         readonly IClientStreamWriter<TRequest> requestStream;
33         readonly Task<TResponse> responseAsync;
34         readonly AsyncCallState callState;
35 
36         /// <summary>
37         /// Creates a new AsyncClientStreamingCall object with the specified properties.
38         /// </summary>
39         /// <param name="requestStream">Stream of request values.</param>
40         /// <param name="responseAsync">The response of the asynchronous call.</param>
41         /// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
42         /// <param name="getStatusFunc">Delegate returning the status of the call.</param>
43         /// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
44         /// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)45         public AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream,
46                                         Task<TResponse> responseAsync,
47                                         Task<Metadata> responseHeadersAsync,
48                                         Func<Status> getStatusFunc,
49                                         Func<Metadata> getTrailersFunc,
50                                         Action disposeAction)
51         {
52             this.requestStream = requestStream;
53             this.responseAsync = responseAsync;
54             this.callState = new AsyncCallState(responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction);
55         }
56 
57         /// <summary>
58         /// Creates a new AsyncClientStreamingCall object with the specified properties.
59         /// </summary>
60         /// <param name="requestStream">Stream of request values.</param>
61         /// <param name="responseAsync">The response of the asynchronous call.</param>
62         /// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
63         /// <param name="getStatusFunc">Delegate returning the status of the call.</param>
64         /// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
65         /// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
66         /// <param name="state">State object for use with the callback parameters.</param>
AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync, Func<object, Task<Metadata>> responseHeadersAsync, Func<object, Status> getStatusFunc, Func<object, Metadata> getTrailersFunc, Action<object> disposeAction, object state)67         public AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream,
68                                         Task<TResponse> responseAsync,
69                                         Func<object, Task<Metadata>> responseHeadersAsync,
70                                         Func<object, Status> getStatusFunc,
71                                         Func<object, Metadata> getTrailersFunc,
72                                         Action<object> disposeAction,
73                                         object state)
74         {
75             this.requestStream = requestStream;
76             this.responseAsync = responseAsync;
77             this.callState = new AsyncCallState(responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction, state);
78         }
79 
80         /// <summary>
81         /// Asynchronous call result.
82         /// </summary>
83         public Task<TResponse> ResponseAsync
84         {
85             get
86             {
87                 return this.responseAsync;
88             }
89         }
90 
91         /// <summary>
92         /// Asynchronous access to response headers.
93         /// </summary>
94         public Task<Metadata> ResponseHeadersAsync
95         {
96             get
97             {
98                 return callState.ResponseHeadersAsync();
99             }
100         }
101 
102         /// <summary>
103         /// Async stream to send streaming requests.
104         /// </summary>
105         public IClientStreamWriter<TRequest> RequestStream
106         {
107             get
108             {
109                 return requestStream;
110             }
111         }
112 
113         /// <summary>
114         /// Allows awaiting this object directly.
115         /// </summary>
116         /// <returns></returns>
GetAwaiter()117         public TaskAwaiter<TResponse> GetAwaiter()
118         {
119             return responseAsync.GetAwaiter();
120         }
121 
122         /// <summary>
123         /// Gets the call status if the call has already finished.
124         /// Throws InvalidOperationException otherwise.
125         /// </summary>
GetStatus()126         public Status GetStatus()
127         {
128             return callState.GetStatus();
129         }
130 
131         /// <summary>
132         /// Gets the call trailing metadata if the call has already finished.
133         /// Throws InvalidOperationException otherwise.
134         /// </summary>
GetTrailers()135         public Metadata GetTrailers()
136         {
137             return callState.GetTrailers();
138         }
139 
140         /// <summary>
141         /// Provides means to cleanup after the call.
142         /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything.
143         /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
144         /// As a result, all resources being used by the call should be released eventually.
145         /// </summary>
146         /// <remarks>
147         /// Normally, there is no need for you to dispose the call unless you want to utilize the
148         /// "Cancel" semantics of invoking <c>Dispose</c>.
149         /// </remarks>
Dispose()150         public void Dispose()
151         {
152             callState.Dispose();
153         }
154     }
155 }
156