• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2019 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  */
18 
19 /**
20  * \file GRPCInterceptor.h
21  * API for interceptors implementation. This feature is currently EXPERIMENTAL and is subject to
22  * breaking changes without prior notice.
23  *
24  * The interceptors in the gRPC system forms a chain. When a call is made by the user, each
25  * interceptor on the chain has chances to react to events of the call and make necessary
26  * modifications to the call's parameters, data, metadata, or flow.
27  *
28  * \verbatim
29                                      -----------
30                                     | GRPCCall2 |
31                                      -----------
32                                           |
33                                           |
34                              --------------------------
35                             | GRPCInterceptorManager 1 |
36                              --------------------------
37                             | GRPCInterceptor 1        |
38                              --------------------------
39                                           |
40                                          ...
41                                           |
42                              --------------------------
43                             | GRPCInterceptorManager N |
44                              --------------------------
45                             | GRPCInterceptor N        |
46                              --------------------------
47                                           |
48                                           |
49                                  ------------------
50                                 | GRPCCallInternal |
51                                  ------------------
52    \endverbatim
53  *
54  * The chain of interceptors is initialized when the corresponding GRPCCall2 object or proto call
55  * object (GRPCUnaryProtoCall and GRPCStreamingProtoCall) is initialized. The initialization of the
56  * chain is controlled by the property interceptorFactories in the callOptions parameter of the
57  * corresponding call object. Property interceptorFactories is an array of
58  * id<GRPCInterceptorFactory> objects provided by the user. When a call object is initialized, each
59  * interceptor factory generates an interceptor object for the call. gRPC internally links the
60  * interceptors with each other and with the actual call object. The order of the interceptors in
61  * the chain is exactly the same as the order of factory objects in interceptorFactories property.
62  * All requests (start, write, finish, cancel, receive next) initiated by the user will be processed
63  * in the order of interceptors, and all responses (initial metadata, data, trailing metadata, write
64  * data done) are processed in the reverse order.
65  *
66  * Each interceptor in the interceptor chain should behave as a user of the next interceptor, and at
67  * the same time behave as a call to the previous interceptor. Therefore interceptor implementations
68  * must follow the state transition of gRPC calls and must also forward events that are consistent
69  * with the current state of the next/previous interceptor. They should also make sure that the
70  * events they forwarded to the next and previous interceptors will, in the end, make the neighbour
71  * interceptor terminate correctly and reaches "finished" state. The diagram below shows the state
72  * transitions. Any event not appearing on the diagram means the event is not permitted for that
73  * particular state.
74  *
75  * \verbatim
76                                         writeData
77                                     receiveNextMessages
78                                  didReceiveInitialMetadata
79                                       didReceiveData
80                                        didWriteData                   receiveNextmessages
81              writeData  -----             -----                 ----  didReceiveInitialMetadata
82    receiveNextMessages |     |           |     |               |    | didReceiveData
83                        |     V           |     V               |    V didWriteData
84                  -------------  start   ---------   finish    ------------
85                 | initialized | -----> | started | --------> | half-close |
86                  -------------          ---------             ------------
87                        |                     |                      |
88                        |                     | didClose             | didClose
89                        |cancel               | cancel               | cancel
90                        |                     V                      |
91                        |                 ----------                 |
92                         --------------> | finished | <--------------
93                                          ----------
94                                           |      ^ writeData
95                                           |      | finish
96                                            ------  cancel
97                                                    receiveNextMessages
98    \endverbatim
99  *
100  * An interceptor must forward responses to its previous interceptor in the order of initial
101  * metadata, message(s), and trailing metadata. Forwarding responses out of this order (e.g.
102  * forwarding a message before initial metadata) is not allowed.
103  *
104  * Events of requests and responses are dispatched to interceptor objects using the interceptor's
105  * dispatch queue. The dispatch queue should be serial queue to make sure the events are processed
106  * in order. Interceptor implementations must derive from GRPCInterceptor class. The class makes
107  * some basic implementation of all methods responding to an event of a call. If an interceptor does
108  * not care about a particular event, it can use the basic implementation of the GRPCInterceptor
109  * class, which simply forward the event to the next or previous interceptor in the chain.
110  *
111  * The interceptor object should be unique for each call since the call context is not passed to the
112  * interceptor object in a call event. However, the interceptors can be implemented to share states
113  * by receiving state sharing object from the factory upon construction.
114  */
115 
116 #import "GRPCCall.h"
117 #import "GRPCDispatchable.h"
118 
119 NS_ASSUME_NONNULL_BEGIN
120 
121 @class GRPCInterceptorManager;
122 @class GRPCInterceptor;
123 @class GRPCRequestOptions;
124 @class GRPCCallOptions;
125 @protocol GRPCResponseHandler;
126 
127 /**
128  * The GRPCInterceptorInterface defines the request events that can occur to an interceptor.
129  */
130 @protocol GRPCInterceptorInterface <NSObject, GRPCDispatchable>
131 
132 /**
133  * To start the call. This method will only be called once for each instance.
134  */
135 - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
136                     callOptions:(GRPCCallOptions *)callOptions;
137 
138 /**
139  * To write data to the call.
140  */
141 - (void)writeData:(id)data;
142 
143 /**
144  * To finish the stream of requests.
145  */
146 - (void)finish;
147 
148 /**
149  * To cancel the call.
150  */
151 - (void)cancel;
152 
153 /**
154  * To indicate the call that the previous interceptor is ready to receive more messages.
155  */
156 - (void)receiveNextMessages:(NSUInteger)numberOfMessages;
157 
158 @end
159 
160 /**
161  * An interceptor factory object is used to create interceptor object for the call at the call
162  * start time.
163  */
164 @protocol GRPCInterceptorFactory
165 
166 /**
167  * Create an interceptor object. gRPC uses the returned object as the interceptor for the current
168  * call
169  */
170 - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
171 
172 @end
173 
174 /**
175  * GRPCInterceptorManager is a helper class to forward messages between the interceptors. The
176  * interceptor manager object retains reference to the next and previous interceptor object in the
177  * interceptor chain, and forward corresponding events to them.
178  *
179  * All methods except the initializer of the class can only be called on the manager's dispatch
180  * queue. Since the manager's dispatch queue targets corresponding interceptor's dispatch queue, it
181  * is also safe to call the manager's methods in the corresponding interceptor instance's methods
182  * that implement GRPCInterceptorInterface.
183  *
184  * When an interceptor is shutting down, it must invoke -shutDown method of its corresponding
185  * manager so that references to other interceptors can be released and proper clean-up is made.
186  */
187 @interface GRPCInterceptorManager : NSObject <GRPCInterceptorInterface, GRPCResponseHandler>
188 
189 - (instancetype)init NS_UNAVAILABLE;
190 
191 + (instancetype)new NS_UNAVAILABLE;
192 
193 - (nullable instancetype)initWithFactories:(nullable NSArray<id<GRPCInterceptorFactory>> *)factories
194                        previousInterceptor:(nullable id<GRPCResponseHandler>)previousInterceptor
195                                transportID:(GRPCTransportID)transportID;
196 
197 /**
198  * Notify the manager that the interceptor has shut down and the manager should release references
199  * to other interceptors and stop forwarding requests/responses.
200  */
201 - (void)shutDown;
202 
203 // Methods to forward GRPCInterceptorInterface calls to the next interceptor
204 
205 /** Notify the next interceptor in the chain to start the call and pass arguments */
206 - (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions
207                             callOptions:(GRPCCallOptions *)callOptions;
208 
209 /** Pass a message to be sent to the next interceptor in the chain */
210 - (void)writeNextInterceptorWithData:(id)data;
211 
212 /** Notify the next interceptor in the chain to finish the call */
213 - (void)finishNextInterceptor;
214 
215 /** Notify the next interceptor in the chain to cancel the call */
216 - (void)cancelNextInterceptor;
217 
218 /** Notify the next interceptor in the chain to receive more messages */
219 - (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages;
220 
221 // Methods to forward GRPCResponseHandler callbacks to the previous object
222 
223 /** Forward initial metadata to the previous interceptor in the chain */
224 - (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata;
225 
226 /** Forward a received message to the previous interceptor in the chain */
227 - (void)forwardPreviousInterceptorWithData:(nullable id)data;
228 
229 /** Forward call close and trailing metadata to the previous interceptor in the chain */
230 - (void)forwardPreviousInterceptorCloseWithTrailingMetadata:
231             (nullable NSDictionary *)trailingMetadata
232                                                       error:(nullable NSError *)error;
233 
234 /** Forward write completion to the previous interceptor in the chain */
235 - (void)forwardPreviousInterceptorDidWriteData;
236 
237 @end
238 
239 /**
240  * Base class for a gRPC interceptor. The implementation of the base class provides default behavior
241  * of an interceptor, which is simply forward a request/callback to the next/previous interceptor in
242  * the chain. The base class implementation uses the same dispatch queue for both requests and
243  * callbacks.
244  *
245  * An interceptor implementation should inherit from this base class and initialize the base class
246  * with [super initWithInterceptorManager:dispatchQueue:] for the default implementation to function
247  * properly.
248  */
249 @interface GRPCInterceptor : NSObject <GRPCInterceptorInterface, GRPCResponseHandler>
250 
251 - (instancetype)init NS_UNAVAILABLE;
252 + (instancetype)new NS_UNAVAILABLE;
253 
254 /**
255  * Initialize the interceptor with the next interceptor in the chain, and provide the dispatch queue
256  * that this interceptor's methods are dispatched onto.
257  */
258 - (nullable instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
259                                       dispatchQueue:(dispatch_queue_t)dispatchQueue;
260 
261 // Default implementation of GRPCInterceptorInterface
262 
263 - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
264                     callOptions:(GRPCCallOptions *)callOptions;
265 - (void)writeData:(id)data;
266 - (void)finish;
267 - (void)cancel;
268 - (void)receiveNextMessages:(NSUInteger)numberOfMessages;
269 
270 // Default implementation of GRPCResponeHandler
271 
272 - (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata;
273 - (void)didReceiveData:(id)data;
274 - (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
275                                error:(nullable NSError *)error;
276 - (void)didWriteData;
277 
278 @end
279 
280 NS_ASSUME_NONNULL_END
281