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